解析运算符并在JavaScript中对它们进行评估

 凹凸曼00威威_694 发布于 2023-02-12 21:26

我想解析一个包含if语句并评估其输出的字符串.

我可以得到评估部分,但其他人对我来说太复杂了.

请看以下示例:

if $a == 10 && ($b == '5' || $c == 'test')

if $x != 10 || $y == false

if $z < 10

我想让它们在数组中 - 也就是说,我想要的相应示例的输出将是:

[ [ '$a', '==', '10' ], '&&', [ [ '$b', '==', '5' ], '||', [ '$c', '==', 'test' ] ] ]

[ [ '$x', '!=', '10' ], '||', [ '$y', '==', 'false' ] ]

[ '$z', '<', '10' ]

我想我要求太多的逻辑/代码,但如果有人能帮助我,这将是很好的.使用正则表达式或正常的字符串解析是可以的.

1 个回答
  • 如果您只是想解析字符串,那么有很多JavaScript解析库可以为您完成.例如,您可以使用acorn将有效的 JavaScript代码解析为Mozilla AST.您还可以使用escodegen将其转换回字符串.

    不幸的是,你的字符串似乎不是有效的JavaScript代码,但如果你删除if每个字符串的开头,那么你绝对可以使用acorn解析字符串.输出将是AST,这不是您正在寻找的,但您可以轻松地将其转换为您想要的格式.

    然而,对于这样一个微不足道的用例,使用一个完整的解析器是我的拙见.例如,如果您只想评估字符串,则可以使用Function构造函数,如下所示:

    function read(expression) {
        var variables = expression.match(/\$\w+/g);
        var length = variables.length;
        var uniqueVariables = [];
        var index = 0;
    
        while (index < length) {
            var variable = variables[index++];
            if (uniqueVariables.indexOf(variable) < 0)
                uniqueVariables.push(variable);
        }
    
        return Function.apply(null, uniqueVariables.concat("return " + expression));
    }
    

    read函数允许您按如下方式读取表达式:

    var condition = read("$a == 10 && ($b == '5' || $c == 'test')");
    

    您现在可以使用以下condition功能:

    alert(condition(10, "10", "test")); // true
    alert(condition(5, "10", "test")); // false
    

    请亲自查看演示:http://jsfiddle.net/ZnUh2/

    当然,您需要删除if所有字符串的开头才能阅读它们.这可以通过使用string.slice(2)删除来轻松完成if.

    如果你一直都在努力将你的字符串转换成数组,那么这将需要更多的工作,但是可以通过使用像Lexer这样的词法分析器轻松完成.您需要做的第一件事是为不同类型的令牌编写一些规则:

    var lexer = new Lexer;
    
    lexer.addRule(/\s+/, function () { /* skip whitespace */ });
    
    lexer.addRule(/if\b/g, function () { /* skip the if keyword */ });
    
    // match opening parentheses
    lexer.addRule(/\(/, function () { return "("; });
    
    // match closing parentheses
    lexer.addRule(/\)/, function () { return ")"; });
    
    // match any other token
    lexer.addRule(/[^\s\(\)]+/, function (lexeme) { return lexeme; });
    

    请注意,此词法分析器期望每个标记(括号除外)在它们之间都有空格.例如,$a==10将被视为一个令牌,但$a == 10将被视为3个令牌.

    接下来你需要的是一个基本的解析器.您可以手动实现,但是自己编写所有运算符优先级规则会很麻烦.相反,我建议您使用基于Dijkstra的分流码算法的以下解析器.

    我们现在可以创建一个解析器,如下所示:

    var relational = {
        precedence: 3,
        associativity: "left"
    };
    
    var equality = {
        precedence: 2,
        associativity: "left"
    };
    
    var parser = new Parser({
        "<":  relational,
        "<=": relational,
        ">":  relational,
        ">=": relational,
        "==": equality,
        "!=": equality,
        "&&": {
            precedence: 1,
            associativity: "right"
        },
        "||": {
            precedence: 0,
            associativity: "right"
        }
    });
    

    最后,我们编写代码将词法分析器连接到解析器并生成所需的输出:

    function parse(string) {
        lexer.setInput(string);
    
        var tokens = [], token;
    
        while (token = lexer.lex()) tokens.push(token);
        tokens = parser.parse(tokens);
    
        var stack = [], length = tokens.length, index = 0;
    
        while (index < length) {
            token = tokens[index++];
    
            switch (token) {
            case "<":
            case "<=":
            case ">":
            case ">=":
            case "==":
            case "!=":
            case "&&":
            case "||":
                var b = stack.pop();
                var a = stack.pop();
                stack.push([a, token, b]);
                break;
            default:
                stack.push(token);
            }
        }
    
        return stack.length && stack[0];
    }
    

    而已.现在,您可以将字符串解析为数组,如下所示:

    var array = parse("if $a == 10 && ($b == '5' || $c == 'test')");
    

    要查看您可以使用的输出JSON.stringify.请亲自观看演示:http://jsfiddle.net/d2UYZ/3/

    2023-02-12 21:33 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有