背景
任务
解决每次编辑会重新生成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了。