【问题标题】:Why is my program only detecting integer tokens in NodeJS?为什么我的程序只检测 NodeJS 中的整数标记?
【发布时间】:2022-02-16 15:27:46
【问题描述】:

我决定尝试制作一个语言标记器(甚至不知道这是否是一个真实的单词)并制作了大约 4 个标记,成功标记了一个带有换行符和多个空格等的完整程序,但我只是从头开始我遇到了问题;我目前有两个令牌,intvariableSet。正在读取的程序具有 1 sv 1 2 的内容作为测试,并且标记器返回一个 int, int, int, int 数组,其中 sv 的值为 1

const code = `1 sv 1 2`

var validTokens = require("./tokens"); // just an object with the structure tokenName: RegExp object

function reverseTokenSearch(regex){
    for (const [index, [key, value]] of Object.entries(Object.entries(validTokens))) {
        if (value === regex){
            return key;
        }
    }
    return false;
}

function throughTokens (code,lastidx=0) {
    for (const tokentype in validTokens){ // loop through all of the valid tokens
        validTokens[tokentype].lastIndex = lastidx;
        const searchresult = validTokens[tokentype]
        const tokenresult = searchresult.exec(code.toString());
        if (tokenresult) {
            return [searchresult, tokenresult[0], tokenresult.index, lastidx+tokenresult[0].length+1, tokenresult.groups]
        }
    }
}

function resetIndexes (){
    for (const tt in validTokens){
        validTokens[tt].lastidx = 0;
    }
}
resetIndexes();
var lst = 0
var tokens = []
var res = 1;
console.log("\ntokenizer; original input:\n"+code+"\n");
while (lst !== undefined && lst !== null){
    if (lst > code.length){
        console.error("Fatal error: tokenizer over-reached program length.")
        process.exit(1)
    }
    const res = throughTokens(code,lst);
    if(res){
        console.log(res,lst)
        const current = []
        current[0] = reverseTokenSearch(res[0])
        current[1] = res[1]
        const currentidx = 2
        for (const x in res[4]) {
            current[currentidx] = x;
        }
        tokens.push(current)
        lst = res[3]
    } else {
        lst = null
    }
}
console.log(tokens)
// What outputs:
/*
tokenizer; original input:
1 sv 1 2

[ /\d+/g { lastidx: 0 }, '1', 0, 2, undefined ] 0
[ /\d+/g { lastidx: 0 }, '1', 5, 4, undefined ] 2
[ /\d+/g { lastidx: 0 }, '1', 5, 6, undefined ] 4
[ /\d+/g { lastidx: 0 }, '2', 7, 8, undefined ] 6
[ [ 'int', '1' ], [ 'int', '1' ], [ 'int', '1' ], [ 'int', '2' ] ]
*/

我认为这是因为数组的顺序,但我不知道从哪里开始修复它,并且非常感谢朝着正确的方向推动。 (编辑):我尝试删除 RegExp 对象上的“g”标志,但它所做的只是让程序陷入无限循环。

【问题讨论】:

  • 可以显示validTokens的内容吗?
  • module.exports = { int: new RegExp("\\d+","g"), variableSet: new RegExp("sv","g"), }

标签: javascript node.js regex tokenize


【解决方案1】:

问题是您默默地假设正则表达式找到的每个匹配项都将从lastidx 开始,但情况并非总是如此。如果你在从throughTokens返回之前登录tokenresultlastidx,你会看到:

0
[ '1', index: 0, input: '1 sv 1 2', groups: undefined ] 
2
[ '1', index: 5, input: '1 sv 1 2', groups: undefined ]
4
[ '1', index: 5, input: '1 sv 1 2', groups: undefined ]
6
[ '2', index: 7, input: '1 sv 1 2', groups: undefined ]

在第二次迭代中,匹配位于索引 5,但您假设它位于索引 2,但事实并非如此(因此您也错误地将 lastidx 增加到 4)。您还在throughTokens 的末尾假设每个匹配项后面都有一个空格,这对于最后一个标记也是不正确的。

修复此代码的最简单方法是替换

//if (tokenresult) { // replace in throughTokens with below
if (tokenresult && tokenresult.index === lastidx) {

确保您在正确的位置匹配,然后在主循环中进行匹配

//while (lst !== undefined && lst !== null){ // replace with below
while (lst !== undefined && lst !== null && lst < code.length){

正确处理输入的结尾。

通过这些更改,我们之前添加的打印输出将是

0
[ '1', index: 0, input: '1 sv 1 2', groups: undefined ]
2
[ 'sv', index: 2, input: '1 sv 1 2', groups: undefined ]
5
[ '1', index: 5, input: '1 sv 1 2', groups: undefined ]
7
[ '2', index: 7, input: '1 sv 1 2', groups: undefined ]

这是正确的,输出将是

[
    [ 'int', '1' ],
    [ 'variableSet', 'sv' ],
    [ 'int', '1' ],
    [ 'int', '2' ]
]

建议

这段代码还有很多其他逻辑和编程问题,我不会深入探讨,但我的建议是仔细阅读每一段代码,了解它的作用以及它是否可以以更简单的方式完成。

一般来说,不是返回包含数据[d1, d2, d3, ...] 的数组,而是返回具有命名属性{ result: d1, index: d2, ... } 的对象。然后其他人更容易理解您的代码。还要通过方法的命名。

就这种方法而言,如果你知道每个token后面都会有一个空格,那么只提取当前token并发送到throughToken。然后,您可以使该函数更高效、更可靠地防止错误。

【讨论】:

    猜你喜欢
    • 2018-09-04
    • 1970-01-01
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多