我是一名新手程序员,在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,但请注意它可能会崩溃。如果您有任何其他建议,请告诉我。
感谢您的帮助。
答案 0 :(得分:1)
由于可用的排列和组合的数量,数学表达式不会使用正则表达式进行解析和计算。到目前为止更快的方法是POST FIX表示法,因为其他表示法不如此快。正如他们在维基百科上提到的那样:
反向波兰符号与代数的比较测试 记法,反向波兰语被发现导致更快 计算,有两个原因。因为反向波兰计算器 不需要将表达式括起来,需要的操作更少 输入以执行典型计算。另外,用户 反向波兰计算器比其他类型的计算器犯错误少 计算器。后来的研究澄清了速度的提高 从反向波兰表示法可能归因于较小的数字 按键需要输入这种符号,而不是更小的符号 对用户的认知负担。然而,轶事证据表明 反向波兰表示法比用户更难学习 代数符号。
此外,您还可以看到其他符号仍然比正则表达式更好。
因此,我建议您将算法更改为更有效的算法,我个人更喜欢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。我没有将任何这些集成到您现有的计算器界面中,但是如果您能够理解如何使用解析器