forTeam/js/Dict.js

287 lines
11 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 字典对象
const Word = require("./Word")
const WordGroup = require("./WordGroup")
const {shakeDom, log, shakeDomFocus} = require('./Utility')
const os = require('os')
class Dict {
constructor(fileContent, fileName, filePath) {
this.dictTypeName = 'Dict'
this.filePath = filePath // 文件路径
this.fileName = fileName // 文件名字
this.header = null // 文件头部内容
this.wordsOrigin = [] // 文件词条数组
this.lastIndex = 0 // 最后一个Word Index 的值,用于新添加词时,作为唯一的 id 传入
this.lastGroupIndex = 0 // 最后一个WordGroup Index 的值,用于新添加词时,作为唯一的 id 传入
this.isGroupMode = false // 识别码表是否为分组形式的
let indexEndOfHeader = fileContent.indexOf('...')
if (indexEndOfHeader < 0){
log('文件格式错误,没有 ... 这一行')
} else {
this.indexEndOfHeader = indexEndOfHeader + 3
this.header = fileContent.substring(0, this.indexEndOfHeader)
this.isGroupMode = this.header.includes('dict_grouped: true') // 根据有没有这一段文字进行判断,是否为分组形式的码表
let body = fileContent.substring(this.indexEndOfHeader)
this.wordsOrigin = this.isGroupMode? this.getDictWordsInGroupMode(body): this.getDictWordsInNormalMode(body)
}
}
// 总的词条数量
get countDictOrigin(){
if (this.isGroupMode){
let countOrigin = 0
this.wordsOrigin.forEach(group => {
countOrigin = countOrigin + group.dict.length
})
return countOrigin
} else {
return this.wordsOrigin.length
}
}
// 返回所有 word
getDictWordsInNormalMode(fileContent){
let startPoint = new Date().getTime()
let EOL = this.getFileEOLFrom(fileContent)
let lines = fileContent.split(EOL) // 拆分词条与编码成单行
this.lastIndex = lines.length
let linesValid = lines.filter(item => item.indexOf('\t') > -1) // 选取包含 \t 的行
let words = []
linesValid.forEach((item, index) => {
let currentWord = getWordFromLine(index, item)
words.push(currentWord) // 获取词条
})
log(`处理yaml码表文件完成${words.length } ${this.isGroupMode? '组': '条'},用时 ${new Date().getTime() - startPoint} ms`)
return words
}
// 返回 word 分组
getDictWordsInGroupMode(fileContent){
let startPoint = new Date().getTime()
let EOL = this.getFileEOLFrom(fileContent)
let lines = fileContent.split(EOL) // 拆分词条与编码成单行
let wordsGroup = [] // 总分组
let temp = null // 第一个分组
let lastItemIsEmptyLine = false // 上一条是空,用于循环中判断是否需要新起一个 WordGroup
this.lastIndex = lines.length
lines.forEach((item, index) => {
if (item.startsWith('##')) { // 注释分组
if (temp && temp.groupName) { // 如果上一个已经有名字了,说明需要保存
wordsGroup.push(temp)
}
temp = new WordGroup(this.lastGroupIndex++, item.substring(3).trim())
lastItemIsEmptyLine = false
} else if (item.indexOf('\t') > -1) { // 是词条
if (!temp){ // 第一行是词条时,没有分组名时
temp = new WordGroup(this.lastGroupIndex++)
}
temp.dict.push(getWordFromLine(index, item))
lastItemIsEmptyLine = false
} else if (item.startsWith('#')) { // 注释
log(item)
lastItemIsEmptyLine = false
} else {
// 为空行时
if (lastItemIsEmptyLine){
// 上行和本行都是空行
} else {
if (temp){
temp.groupName = temp.groupName || '未命名'
wordsGroup.push(temp)
temp = new WordGroup(this.lastGroupIndex++)
}
}
lastItemIsEmptyLine = true
}
})
log(`处理yaml码表文件完成${wordsGroup.length } ${this.isGroupMode? '组': '条'},用时 ${new Date().getTime() - startPoint} ms`)
if (temp){
if (temp.dict.length > 0){
wordsGroup.push(temp) // 加上最后一个
}
return wordsGroup
} else {
return [] // 文件内容为空时
}
}
// 判断码表文件的换行符是 \r\n 还是 \n
getFileEOLFrom(fileContent){
if(fileContent.indexOf('\r\n') > 0){
return '\r\n'
} else {
return '\n'
}
}
// 排序
sort(groupIndex){
let startPoint = new Date().getTime()
if (this.isGroupMode){ // group mode
if (groupIndex !== -1){ // -1 代表全部
this.wordsOrigin[groupIndex].dict.sort((a,b) => a.code < b.code ? -1: 1)
} else {
this.wordsOrigin.forEach(group => {
group.dict.sort((a,b) => a.code < b.code ? -1: 1)
})
}
} else {
this.wordsOrigin.sort((a,b) => a.code < b.code ? -1: 1)
}
log(`Sort 用时 ${new Date().getTime() - startPoint} ms`)
}
/**
* 添加新 Word
* @param word Word
* @param groupIndex Number
*/
addNewWord(word, groupIndex){
if(this.isGroupMode){
if (groupIndex !== -1){
this.wordsOrigin[groupIndex].dict.push(word)
} else {
let newWordGroup = new WordGroup(this.lastGroupIndex++,'- 未命名 -',[word])
this.wordsOrigin.unshift(newWordGroup) // 添加到第一组
}
} else {
this.addWordToDictInOrder(word)
}
this.lastIndex = this.lastIndex + 1 // 新加的词添加后, lastIndex + 1
}
// 依次序添加 words
addWordsInOrder(words, groupIndex){
let startPoint = new Date().getTime()
if (this.isGroupMode && groupIndex !== -1){
this.addWordToDictInOrderWithGroup(words, groupIndex)
} else {
words.forEach(word => {
this.addWordToDictInOrder(word)
})
}
log(`添加 ${words.length } 条词条到指定码表, 用时 ${new Date().getTime() - startPoint} ms`)
}
// 依次序添加 word
addWordToDictInOrder(word){
let insetPosition = null // 插入位置 index
for (let i=0; i<this.wordsOrigin.length-1; i++){ // -1 为了避免下面 i+1 为 undefined
if (word.code >= this.wordsOrigin[i] && word.code <= this.wordsOrigin[i+1].code){
insetPosition = i + 1
break
}
}
if (!insetPosition){ // 没有匹配到任何位置,添加到结尾
insetPosition = this.wordsOrigin.length
}
let wordInsert = word.clone() // 断开与别一个 dict 的引用链接,新建一个 word 对象,不然两个 dict 引用同一个 word
wordInsert.setId(this.lastIndex++) // 给新的 words 一个新的唯一 id
this.wordsOrigin.splice(insetPosition, 0, wordInsert)
}
// 依次序添加 word groupMode
addWordToDictInOrderWithGroup(words, groupIndex){
let dictWords = this.wordsOrigin[groupIndex].dict
log('TODO: add to group')
words.forEach(word => {
let insetPosition = null // 插入位置 index
for (let i=0; i<dictWords.length-1; i++){ // -1 为了避免下面 i+1 为 undefined
if (word.code >= dictWords[i] && word.code <= dictWords[i+1].code){
insetPosition = i + 1
break
}
}
if (!insetPosition){ // 没有匹配到任何位置,添加到结尾
insetPosition = dictWords.length
}
let wordInsert = word.clone() // 断开与别一个 dict 的引用链接,新建一个 word 对象,不然两个 dict 引用同一个 word
wordInsert.id = dictWords.length + 1 // 给新的 words 一个新的唯一 id
dictWords.splice(insetPosition, 0, wordInsert)
})
}
// 删除词条
deleteWords(wordIdSet, isDeleteInSelf){ // isDeleteInSelf 在移动词条到自己分组时使用,不删除空的分组
if (this.isGroupMode){
let deleteGroupIds = [] // 记录 words 为 0 的 group最后删除分组
this.wordsOrigin.forEach((group, index) => {
group.dict = group.dict.filter(item => !wordIdSet.has(item.id))
if (group.dict.length === 0){
deleteGroupIds.push(index)
}
})
// config: 是否删除空的分组
if (!isDeleteInSelf){
this.wordsOrigin = this.wordsOrigin.filter((group, index) => !deleteGroupIds.includes(index))
}
} else {
this.wordsOrigin = this.wordsOrigin.filter(item => !wordIdSet.has(item.id))
}
}
addGroupBeforeId(groupIndex){
this.wordsOrigin.splice(groupIndex,0,new WordGroup(this.lastGroupIndex++,'',[],true))
}
// 分组模式:删除分组
deleteGroup(groupId){
log('要删除的分组 id: ',groupId)
this.wordsOrigin = this.wordsOrigin.filter(group => group.id !== groupId)
}
// 转为 yaml String
toYamlString(){
let yamlBody = ''
if (this.isGroupMode){
this.wordsOrigin.forEach(group => {
let tempGroupString = ''
tempGroupString = tempGroupString + `## ${group.groupName}${os.EOL}` // + groupName
group.dict.forEach(item =>{
tempGroupString = tempGroupString + item.toYamlString() + os.EOL
})
yamlBody = yamlBody + tempGroupString + os.EOL // 每组的末尾加个空行
})
return this.header + os.EOL + yamlBody
} else {
let yamlBody = ''
this.wordsOrigin.forEach(item =>{
yamlBody = yamlBody + item.toYamlString() + os.EOL
})
return this.header + os.EOL + yamlBody
}
}
// 在 origin 中调换两个词条的位置
exchangePositionInOrigin(word1, word2){
// 确保 word1 在前
if (parseInt(word1.id) > parseInt(word2.id)){
let temp = word1
word1 = word2
word2 = temp
}
for(let i=0; i<this.wordsOrigin.length; i++){
let tempWord = this.wordsOrigin[i]
if (tempWord.isEqualTo(word1)){
this.wordsOrigin[i] = word2
}
if (tempWord.isEqualTo(word2)){
this.wordsOrigin[i] = word1
}
}
}
}
// 从一条词条字符串中获取 word 对象
function getWordFromLine(index, lineStr){
let wordArray = lineStr.split('\t')
let code = wordArray[1]
let word = wordArray[0]
let priority = wordArray.length > 2 ? wordArray[2] : null
return new Word(index, code, word, priority)
}
module.exports = Dict