【问题标题】:scan string operators - javascript扫描字符串运算符 - javascript
【发布时间】:2014-03-29 16:34:10
【问题描述】:

在计算器中,我特别拥有 4 个输入类型 =“数字”:

<input type = "number" id ="mol" min="1" max="4">
<input type = "number" id ="div" min="1" max="4">
<input type = "number" id ="add" min="1" max="4">
<input type = "number" id ="min" min="1" max="4">

在文本框中,我插入扩展的数学表达式。

<input type = "text" id = "exp" readonly>

数值和运算符都经过了正常的按键。 因此,例如,插入文本框中的表达式是:8*5-9/2+3

现在我希望当我按下等号键时,根据客户赋予操作数的优先级,表达式结果发生变化。

乘法:1
师:4
减法:2
补充:3

-> 40 - 9 / 2 + 3
-> 31 / 2 + 3
-> 31 / 5
-> = 6.2

我认为这是很难实现的。 获取文本框的值并根据操作数的优先级评估结果真的很极端。你有什么建议?

【问题讨论】:

    标签: string operators operator-precedence


    【解决方案1】:

    尝试使用split 方法:http://msdn.microsoft.com/en-us/library/t5az126b(v=vs.94).aspx

    首先拆分具有第一优先级的运算符,然后由第二个运算符拆分每个组,然后由第三个运算符拆分每个子组,并由第四个运算符拆分每个子子组。然后将运算符应用于向上移动的组。

    概念示例(不是您需要的完整代码,但应该给出一个想法):

    var expression = "8*5-9/2+3"; // Get this from the data
    var operator1Groups = expression.split("*"); // Instead of hardcoding this, retrieve which operator has highest priority from the data
    for (var i in operator1Groups) {
        var operator2Groups = operator1Groups[i].split("+"); // Similarly, don't hardcode the operator
        // And so on...
        // Once you get to the lowest operator, start applying the operator to each group
    }
    

    【讨论】:

    • 这将如何处理具有相同优先级的两个运算符?
    • OP 没有说明两个运算符可以具有相同的优先级。但是,它仍然可以工作。在这种情况下,您可以拆分多个分隔符。这是一种方法:stackoverflow.com/questions/19313541/…
    • 我创建了这个数组:var Array = ['+', '-', '*', '/'];但是我不明白你的代码是如何运行的,你可以给我一个我之前输入的规范的实际例子吗?
    【解决方案2】:

    执行此操作的方法是使用Operator Precedence Parser。它们通常使用 Djikstra 的Shunting-yard Algorithm 实现。您可以通过将运算符和优先级加载到列表中然后运行算法来指定优先级:

    function parse(inputExpression, operators) {
        // Strip out anything that isn't a number or a math operator
        var tokens = inputExpression
                    .replace(/[^0-9+\-*\/()]/g, '')
                    .split(/([+\-*\/()])/)
                    .filter(function(x) { return x != ""; });
    
        var outputQ = []; // push = push, pop = pop
        var operStk = []; // enqueue = push, dequeue = shift
    
        function top(stack) { return stack[stack.length-1]; }
    
        while(tokens.length !== 0) {
            var token = tokens.shift();
            if(!isNaN(Number(token))) {
                outputQ.push(token);
            } else if (operators.hasOwnProperty(token)) {
                while(operators[token] >= operators[top(operStk)])
                    outputQ.push(operStk.pop());
                operStk.push(token);
            } else if (token == '(') {
                operStk.push(token);
            } else if (token == ')') {
                while(top(operStk) != '(' && operStk.length != 0)
                    outputQ.push(operStk.pop());
    
                if(operStk.length == 0)
                    return null;
    
                operStk.pop(); // Get rid of the l-paren
            } else {
                console.log("Bad token '" + token + "'");
                return null;
            }
        }
    
        while(operStk.length > 0) 
            outputQ.push(operStk.pop());
    
        return outputQ;
    }
    
    function evaluate(parseResult) {
        if (parseResult === null) return null;
    
        var valueStack = [];
        while(parseResult.length !== 0) {
            var op = parseResult.shift();
            if(!isNaN(Number(op)))
                valueStack.push(Number(op));
            else {
                var val2 = valueStack.pop();
                var val1 = valueStack.pop();
                if(op == '+') {
                    valueStack.push(val1 + val2);
                } else if(op == '-') {
                    valueStack.push(val1 - val2);
                } else if(op == '*') {
                    valueStack.push(val1 * val2);
                } else if(op == '/') {
                    valueStack.push(val1 / val2);
                } else {
                    console.log("Invalid operator '" + op + "'");
                    return null;
                }
            }
        }
    
        if(valueStack.length !== 1) {
            console.log("Invalid stack. Remaining: " + valueStack);
            return null;
        }
    
        return valueStack.pop();
    }
    

    用法:

    var operators = {
        "+": 3,
        "-": 2,
        "*": 1,
        "/": 4
    };
    evaluate(parse("40 - 9 / 2 + 3", operators)); // == 6.2
    

    请注意,这将处理一元减号,因为它很难与 Shunting-yard 一起使用,并且因为您没有要求它的优先级。从好的方面来说,它确实支持括号。

    希望这会有所帮助!

    亚历克斯

    【讨论】:

    • 问题是我必须从文本框中读取表达式。我认为创建 4 个循环会很有用,每个循环都包含用户输入的优先级。所以我订购了向量的元素。我认为这要简单得多。你帮我建?
    • 我将把它作为练习留给你——查看 jQuery 文档以获取阅读文本框/表单字段值的好资源。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 2020-08-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多