调车码算法(在Javascript中),处理负数

时间:2013-06-17 16:04:12

标签: javascript shunting-yard

我在JS中编写了分流码算法,几乎适用于所有场景,但如果我有一个负数场景,那么它会失败,例如,如果我给这个表达式9-(3 *( - 6))然后它不会给出结果......任何提示都会非常感激 ...我不想使用正则表达式。我改为编写了自己的表达式解析器。

我的代码: -

http://jsfiddle.net/min2bro/8ZvGh/20/

     // ========================== Converting string into Array of opeartors & operands including brackets also======
    // for example: if you enter the expression: 9-(5*2)+(7.66/3.21)*3 
    // this would return ['9','-','5','*','2','+','7.66','/','3.21','*','3']


    output = prompt("Enter the expression");


var result = [];
var str = "";
var temp = [];
var expression = [];



  for (i = 0; i < output.length; ++i)

  { 

      if(output[i] != "*" && output[i] != "+" && output[i] != "/" && output[i] != "-" )

       temp.push(output[i]);

      if(output[i] == "*" || output[i] == "+" || output[i] == "-" || output[i] == "/")

      { 
         for(var j = 0; j<= temp.length-1 ; j++ )
         {

             if (temp[j] == '(' || temp[j] == ')')
             { 
                 expression.push(temp[j])
             }
             else
             {
                 str += temp[j];
                 if (temp[j+1] == ")")
                 { expression.push(str);
                    str = "";
                 }
             }
         }

         var temp = [];  
         if (str!="")
         {
             expression.push(str);
         }
         expression.push(output[i]);

      }       

      str = "";

  } 

for(var n = 0 ; n<= temp.length-1 ; n++ )
{

                 if (temp[n] == '(' || temp[n] == ')')
             { 
                 expression.push(temp[n])
             }
             else
             {
                 str += temp[n];
                 if (temp[n+1] == ")")
                 { expression.push(str);
                    str = "";
                 }
             }


}
if (str!="")
         {
             expression.push(str);
         }











// ========================== Converting expression array into output array as defined in shunting algorithm
// for example: if you enter the expression: 9-(5*2)+(7.66/3.21)*3 
// this would return [9,5,2,*,-,7.66,3.21,/,3,*,+]
//==============================================================================

var output = [];   
var stack = [];
var precedence = {'+': 1,'-': 1,'*': 2,'/': 2,'(': 0};

for(var i = 0; i <= (expression.length-1) ; i++)
{
    if(!isNaN(expression[i]))
    {
      output.push((expression[i]));   
    }
    else if(expression[i] == "*" || expression[i] == "/" || expression[i] == "+" || expression[i] == "-" || expression[i] == "(" || expression[i] == ")")
    {
        if(stack == "" && expression[i] != ")")
       {
           stack.push(expression[i]);
       }
        else if(precedence[expression[i]] > precedence[stack[(stack.length -1)]])
       {
        stack.push(expression[i]);
       }
        else if((precedence[expression[i]] <= precedence[stack[stack.length -1]]))
        {   
            if(expression[i] == "(")
            {
                stack.push(expression[i]);
            }
            if(stack[stack.length-1]!="(")
            { 
            for(var k = (stack.length-1); k >= 0 ; k--)  
              { 
                  output.push(stack[k]);
                stack.pop(stack[k]);
              }
                stack.push(expression[i]);
            }
         }

if(expression[i] == ")")
{
    for(var j = (stack.length-1); j > 0 ; j--)
    {  
        if(stack[j]!="(")
          output.push(stack[j]);
          stack.pop(stack[j]);
    }

}
}

    //alert(stack)
    if(i == expression.length-1 && expression[i] != ")")
{
    //alert(stack);
    for(var j = (stack.length-1); j >= 0 ; j--)
    {  
        if(stack[j]!="(")
       output.push(stack[j]);
        stack.pop();
    }

}

}

    //alert(stack);
    for(var j = (stack.length-1); j >= 0 ; j--)
    {  
        if(stack[j]!="(")
       output.push(stack[j]);
    }




//============ Calculate the result===================

var result = [];

  for (i = 0; i < output.length; ++i)
  { 
    t = output[i];
      //alert(t);
    if (!isNaN(t))
      result.push(t);
    else if (t == "(" || result.length < 2)
      return false;
    else 
    {
       //alert(result);
      var rhs = result.pop();
       //alert(rhs);
      var lhs = result.pop();
      // alert(rhs);
      if (t == "+") result.push(parseFloat(lhs) + parseFloat(rhs));
      if (t == "-") result.push(parseFloat(lhs) - parseFloat(rhs));
      if (t == "*") result.push(parseFloat(lhs) * parseFloat(rhs));
      if (t == "/") result.push(parseFloat(lhs) / parseFloat(rhs));
    }
  }
alert(result);

3 个答案:

答案 0 :(得分:2)

好吧,所以我不知道代码的问题是什么。格式不好,而且时间太长。所以我没有读过它。不过,这就是我编写程序的方法:

我将程序拆分为词法分析和解析阶段。这使您的程序更加模块化,更易于理解。我已经编写了通用lexershunting yard parser。所以我会用这些来编写程序。

首先,词法分析器(我知道你不想使用正则表达式并且你编写了自己的表达式解析器,但这是正则表达式适用的东西,所以):

var lexer = new Lexer;

lexer.addRule(/\s+/, function () {
    // skip whitespace
});

lexer.addRule(/[\+\-\*\/\(\)]/, function (lexeme) {
    // punctuators: +, -, *, /, (, ).
    return lexeme;
});

lexer.addRule(/\-?(?:0|[1-9]\d*)(?:\.\d+)?/, function (lexeme) {
    // matches a number
    // may start with an optional minus sign
    // may have an optional decimal part
    return +lexeme;
});

接下来我们有分流码解析器:

var left1 = {
    associativity: "left",
    precedence: 1
};

var left2 = {
    associativity: "left",
    precedence: 2
};

var parser = new Parser({
    "+": left1,
    "-": left1,
    "*": left2,
    "/": left2
});

然后我们将词法分析器连接到解析器:

function parse(input) {
    lexer.setInput(input);
    var tokens = [], token;
    while (token = lexer.lex())
        tokens.push(token);
    return parser.parse(tokens);
}

现在您需要做的就是调用parse函数,如下所示:

var output = parse("9 - (5 * 2) + (7.66 / 3.21) * 3");
alert(JSON.stringify(output)); // [9,5,2,"*","-",7.66,3.21,"/",3,"*","+"]

自己查看输出:http://jsfiddle.net/jwz7z7mL/

它也正确解析负数:

var output = parse("9 - (3 * (-6))");
alert(JSON.stringify(output)); // [9,3,-6,"*","-"]

请参阅演示:http://jsfiddle.net/jwz7z7mL/1/

此外,它处理优先级和关联性规则以摆脱多余的括号:

var output = parse("9 - 3 * -6");
alert(JSON.stringify(output)); // [9,3,-6,"*","-"]

演示:http://jsfiddle.net/jwz7z7mL/2/

希望有所帮助。

答案 1 :(得分:1)

问题的解决方案可能是将条目9-(3*(-6))重写为9-(3*(0-6))以生成-运算符二进制文件。只需使用(-替换字符串中的每个(0-

答案 2 :(得分:0)

在我看来,在'Aadit M Shah'提及的标记化过程中,它不是处理负数的正确方法

我会建议在分流场的algorythm中处理一元+或 - 。只需用一个不同的符号(在我的情况下为'p'或'm')替换一元+或 - 并在评估后缀符号(或RPN)时处理它们。

您可以找到我的C#实现here on GitHub