在算术运算中实现运算符优先级

时间:2017-12-01 10:49:45

标签: javascript

我有一个代码,但它不适用于运算符优先级。它通常在从字符串输入的第一个到最后一个操作符执行。 它在字符串跟随优先级规则(eg."12 * 10 / 5 + 10 - 1" = 33 <- correct answer)时给出正确答案。但它给出了错误的答案,而字符串不遵循优先规则(eg. "15 + 10 * 5 / 10 - 1" = 49 <- wrong answer. actual answer is 19)

代码:

var str="12 * 10 / 5 + 10 - 1";
var res=[],n1=[],num=[],op=[],o1=[];
var result;

res= str.split(" ");
console.error("res",res);
document.write(res.join(",")+"<br>");

for(var i=0;i<res.length;i++)
{
    if(i%2==0)
  {
  num.push(parseInt(res[i]));
  }
  else
  {
  op.push(res[i]);
  } 
}
document.write(num+"<br>");
document.write(op+"<br>");

var myFunction = function(num1,num2,oper){

    var j;
    if(oper=='-'){
      j = num1-num2;
      return j;
    }else if(oper=='+'){
      j = num1+num2;
      return j;
    }else if(oper=='*'){
      j = num1*num2;
      return j;
    }else if(oper=='/'){
      j = num1/num2;
      return j;
    }else{
      j = 0;
      return j;
      } 
    }
 var x=num[0];
 for(var i=1; i<num.length; i++){
    x = myFunction(x,num[i],op[i-1]);
  }

 document.write("result of "+str+" is "+x+"<br>");

3 个答案:

答案 0 :(得分:1)

这是一种方法。我喜欢因为这是我们制作解析器的方式。还有其他提到的方法,通常在使用像lex / yacc这样的解析器生成器时。

正如您所注意到的,有时我们需要保存中间结果以处理表达式的另一部分。这种称为递归下降解析器的方法使用环境自己的堆栈来保存临时结果。另一种方法是使用自己维护堆栈,但这没什么价值。

这也非常灵活。将语法扩展到不同的优先级非常容易。更改下面的parseFactor以解析否定和括号。

function parse(expression) {
  return expression.split(' ')
}

function consumeNumber(tokens) {
  const token = tokens.shift()
  return parseInt(token)
}

function consumeOp(tokens, allowed) {
  const token = tokens[0]
  if (allowed.indexOf(token) >= 0) {
    tokens.shift()
    return token
  }
}

function parseFactor(tokens) {
  return consumeNumber(tokens)
}

function parseTerm(tokens) {
  let value = parseFactor(tokens)
  let op
  while (op = consumeOp(tokens, ['*', '/'])) {
    let nextVal = parseFactor(tokens)
    switch (op) {
      case '*': 
        value *= nextVal
        break
      case '/': 
        value /= nextVal
        break
    }
  }
  return value
}

function parseExpression(tokens) {
  let value = parseTerm(tokens)
  let op
  while (op = consumeOp(tokens, ['+', '-'])) {
    let nextVal = parseTerm(tokens)
    switch (op) {
      case '+': 
        value += nextVal
        break
      case '-': 
        value -= nextVal
        break
    }
  }
  return value
}

function evaluate(expression) {
  const tokens = parse(expression)

  return parseExpression(tokens)
}

evaluate('15 + 10 * 5 / 10 - 1')

答案 1 :(得分:0)

这是一起被黑客攻击(读取:实际上不应该在没有额外工作/错误检查的情况下实际使用)对象,它可以获得两个测试用例的正确答案。我确信这可以改进,并且可能有更好的算法。根据我的评论,它只扫描*/并处理该计算,然后生成包含该结果的新数字/运算符集。我主要是为了好玩而写的。

我没有费心去尝试解析字符串,这只需要一个数字数组和一个运算符数组。

(另外,我得到11.5作为第二次测试的错误结果,无论是手动还是运行代码)

<script>
myCalc = {

  getResult: function(n, o){

    this.numbers = n;
    this.operators = o;

    // keep going until our list of numbers is just the final result
    while( this.numbers.length > 1 )
      this.findNext();

    return this.numbers[0];
  },

  findNext: function(){

    var opIndex = 0;

    // find the next * or / operator
    for(i=0;i<=this.operators.length;i++){

      if( this.operators[i] == '*' || this.operators[i] == '/' ){

        opIndex = i;
        break;
      }
    }

    var opResult = this.doCalc(this.operators[opIndex], this.numbers[opIndex], this.numbers[opIndex+1]);

    // update our main numbers list and splice out the operator we just processed
    // replace "x" with the result, and splice "y"
    this.numbers[opIndex] = opResult;
    this.numbers.splice(opIndex + 1, 1);
    this.operators.splice(opIndex, 1);

    console.log(this.numbers);
    console.log(this.operators);
  },

  doCalc: function(op,x,y){

    switch(op){
      case '*':
        return x * y;
      case '/':
        return x / y;
      case '+':
        return x + y;
      case '-':
        return x - y;
    }

    return 0;
  }
};

console.log(myCalc.getResult([15,10,5,10,1], ['+','*','/','-']));
console.log(myCalc.getResult([12,10,5,10,1], ['*','/','+','-']));
</script>

答案 2 :(得分:-3)

由于之前没人提及过,您只需使用eval函数处理字符串:

var str="15 + 10 * 5 / 10 - 1";
console.log(eval(str));
// logs 19
  

如果参数是表达式,则eval()计算表达式