背景
任务
-
解决每次编辑会重新生成ID的问题
前置工作
-
复制题目时ID冲突,解决方法:粘贴时先触发diff,若文本中已有相同ID,则将当前要粘贴的文本ID去除。 -
改题型时导致已回收数据无法使用,解决方法:修改题型时,重新分配ID。
行动
基于PEG.js改造
动机
-
因为PEG更加严格更加强大,PEG可以成为很好的正则表达式的替代品。例如,一个正则表达式本身是无法匹配嵌套的括号对,因为正则表达式不是递归的,但是PEG却能做到这点。 -
所有的PEG 都能通过使用Parkrat Parser达到线性时间解析,如同上文所述。 -
CFG表达的解析器,比如LR解析器,需要首先进行一个单独的断词步骤。这个步骤根据空白的位置或者发音等等因素把输入分成词。分词是必要的,因为这类解析器使用向前检查来判断上下文无关文法是否匹配要求。PEG不需要单独的断词步骤,断词的规则和其他文法规则可以用同样的方式写在一起。 -
许多CFG固有的存在二义性,即使它们原本要描述的东西并不具有二义性。C, C++, Java里面著名的悬空else问题就是一个例子。这个问题通常都是应用文法之外的一个规则解决。而在PEG里面,因为使用了优先权,所以根本不存在这种问题。
思路
解决 ID 问题
-
有ID文本时,使用文本所记录的ID。 -
无ID文本时,自动按照规则生成ID。
-
什么时候生成ID -
怎么判断ID是否需要写入 -
怎么写入ID
type Location = {
start: { offset: number, line: number, column: number }
end: { offset: number, line: number, column: number }
}
type ASTQuestion = {
id: string | null
title: {
content: object[],
location: Location
}
}
const astQuestion = {
id: 'q-1-abcd' || null,
title: {
content: ['a', 'b'],
location: {
start: { offset: 0, line: 1, column: 1 },
end: { offset: 2, line: 1, column: 3 },
}
}
}
type Question = {
id: string,
title: string,
}
const question = {
id: 'q-1-abcd',
title: 'ab',
}
const refillQid = (text: string, astQuestion, question: Question) {
// 旧文本中没有 id
if (astQuestion.id === null) {
text = insert(text, question.id, astQuestion.title.location)
}
return text
}
这样,我们就可以做到仅向没有ID的题目写入新生成的ID了。
衍生问题
迁移
总结
本篇文章来源于微信公众号: 腾讯CDC体验设计