“+”Quantifier没有做好自己的工作?

时间:2014-06-08 15:06:15

标签: javascript regex match

我是一名新手程序员,在JavaScript中为学校项目制作一个简单的计算器,而不是使用eval()来评估字符串,我创建了自己的函数calculate(exp)

基本上,我的程序使用操作顺序(PEMDAS,或括号,Exponents,乘法/除法,加法/减法)来计算字符串表达式。我的一个正则表达式是这样的(" mdi"用于乘法/除法):

mdi = /(-?\d+(\.\d+)?)([\*\/])(-?\d+(\.\d+)?)/g;    // line 36 on JSFiddle

这是做什么的:

  • -?\d+找到一个整数

  • 如果有一个

    ,则
  • (\.\d+)?会匹配小数

  • [\*\/]匹配使用的运算符(*/进行乘法或除法)

  • /g匹配字符串表达式中的每个出现。

我使用以下代码循环显示此正则表达式:

while((res = mdi.exec(exp)) !== null) {    // line 69 on JSFiddle
    exp = exp.replace(mdi,
        function(match,$1,$3,$4,$5) {
            if($4 == "*")
                return parseFloat($1) * parseFloat($5);
            else
                return parseFloat($1) / parseFloat($5);
        });
    exp = exp.replace(doN,"");    // this gets rid of double negatives
}

然而,这并不是一直有效。它仅适用于绝对值小于10的数字。我不能对24和-5232000321之类的数字执行任何操作,即使正则表达式应该与+量词匹配。它适用于小数字,但当数字大于10时崩溃并耗尽我的大部分CPU。

例如,当输入表达式5*.5时,会输出2.5,但是当您输入75*.5并按回车键时,程序会停止。

我不确定这里发生了什么,因为我无法找到错误的来源因为某些原因 - 即使我console.log()全部都没有显示我的代码调试,但我认为这是正则表达式的错误。发生了什么事?

完整代码(目前为止)位于JSFiddle.net,但请注意它可能会崩溃。如果您有任何其他建议,请告诉我。

感谢您的帮助。

3 个答案:

答案 0 :(得分:1)

由于可用的排列和组合的数量,数学表达式不会使用正则表达式进行解析和计算。到目前为止更快的方法是POST FIX表示法,因为其他表示法不如此快。正如他们在维基百科上提到的那样:

  

反向波兰符号与代数的比较测试   记法,反向波兰语被发现导致更快   计算,有两个原因。因为反向波兰计算器   不需要将表达式括起来,需要的操作更少   输入以执行典型计算。另外,用户   反向波兰计算器比其他类型的计算器犯错误少   计算器。后来的研究澄清了速度的提高   从反向波兰表示法可能归因于较小的数字   按键需要输入这种符号,而不是更小的符号   对用户的认知负担。然而,轶事证据表明   反向波兰表示法比用户更难学习   代数符号。

完整文章:Reverse Polish Notation

此外,您还可以看到其他符号仍然比正则表达式更好。

Calculator Input Methods

因此,我建议您将算法更改为更有效的算法,我个人更喜欢POST FIX。

答案 1 :(得分:1)

问题是

bzp = /^.\d/;
while((res = bzp.exec(result)) !== null) {
  result = result.replace(bzp,
    function($match) {
      console.log($match + " -> 0 + " + $match);
      return "0" + $match;
    });
}

它不断限制前置零。

删除该代码效果很好。

我还清理了您的代码,声明了变量,并使其更易于维护:Demo

答案 2 :(得分:1)

  

如果您有任何其他建议,请告诉我。

正如评论中所指出的,通过迭代应用正则表达式来解析输入是非常特别的。更好的方法是为您的输入语言实际构造grammar并基于此进行解析。这是一个基本匹配输入语言的示例语法:

expr ::= term ( additiveOperator term )*
term ::= factor ( multiplicativeOperator factor )*
expr ::= number | '(' expr ')'

additiveOperator ::= '+' | '-'
multiplicativeOperator ::= '*' | '/'

这里的语法与正则表达式非常相似,其中parenthesese表示组,*表示零次或多次重复,并且|表示替代品。用单引号括起来的符号是文字,而其他一切都是符号。请注意,此语法不处理一元运算符(根据您的帖子,它听起来像假设负数的单个负号,可以由number解析器解析。)

JavaScript有几个解析器生成器库,但我更喜欢组合式样解析器,其中解析器是在运行时功能构建的,而不是必须运行单独的工具来为您的削皮器生成代码。 Parsimmon是一个很好的JavaScript组合解析器,API非常容易包围。

解析器通常返回与解析语法相对应的某种树数据结构(即abstract syntax tree)。然后遍历此数据结构以计算算术表达式的值。

我创建了a fiddle demonstrating parsing and evaluating of arithmetic expressions。我没有将任何这些集成到您现有的计算器界面中,但是如果您能够理解如何使用解析器