在JavaScript中将string评估为mathexpression式

如何parsing和评估一个string中的mathexpression式(例如'1+1' )而不用调用eval(string)来产生它的数值?

用这个例子,我想让函数接受'1+1'并返回2

您可以使用JavaScript Expression Evaluator库 ,它可以让您执行以下操作:

 Parser.evaluate("2 ^ x", { x: 3 }); 

或者mathjs ,它允许像这样的东西:

 math.eval('sin(45 deg) ^ 2'); 

我结束了为我的一个项目selectmathjs。

有人必须parsing这个string。 如果它不是解释器(通过eval ),那么它将需要你,编写一个parsing例程来提取数字expression式中的数字,运算符和其他任何你想要支持的东西。

所以,不,没有任何(简单)的方式没有eval 。 如果您担心安全问题(因为您parsing的input不是来自您控制的源代码),也许可以在将它传递给eval之前检查input的格式(通过白名单正则expression式filter)?

//你可以轻松地做+或 –

 function addbits(s){ var total= 0, s= s.match(/[+\-]*(\.\d+|\d+(\.\d+)?)/g) || []; while(s.length){ total+= parseFloat(s.shift()); } return total; } var string='1+23+4+5-30'; addbits(string) 

更复杂的math使得eval更具吸引力,写起来也更简单。

我最近在C#中完成了这个工作(对我们来说,没有Eval()…),通过在Reverse Polish Notation(简单的位)中计算expression式。 困难的部分实际上是parsing这个string,并将其转换为反向波兰表示法。 我使用了Shunting Yardalgorithm,因为维基百科和伪代码都有很好的例子。 我发现实现它们非常简单,我build议如果您还没有find解决scheme或正在寻找替代scheme。

我去寻找评估mathexpression式的JavaScript库,并find了这两个有前途的候选人:

  • JavaScriptexpression式评估器 :更小,希望更轻。 允许代数expression式,replace和一些函数。

  • mathjs :允许复数,matrix和单位。 内置于浏览器JavaScript和Node.js中

这是我刚刚扔在一起的一个小函数来解决这个问题 – 它通过一次分析string一个字符来build立expression式(虽然它实际上很快)。 这将采取任何mathexpression式(仅限于+, – ,*,/运算符)并返回结果。 它可以处理负值和无限数量的操作。

唯一的“要做”左边是确保它计算*&/之前+& – 。 稍后将添加该function,但现在这就是我所需要的…

 /** * Evaluate a mathematical expression (as a string) and return the result * @param {String} expr A mathematical expression * @returns {Decimal} Result of the mathematical expression * @example * // Returns -81.4600 * expr("10.04+9.5-1+-100"); */ function expr (expr) { var chars = expr.split(""); var n = [], op = [], index = 0, oplast = true; n[index] = ""; // Parse the expression for (var c = 0; c < chars.length; c++) { if (isNaN(parseInt(chars[c])) && chars[c] !== "." && !oplast) { op[index] = chars[c]; index++; n[index] = ""; oplast = true; } else { n[index] += chars[c]; oplast = false; } } // Calculate the expression expr = parseFloat(n[0]); for (var o = 0; o < op.length; o++) { var num = parseFloat(n[o + 1]); switch (op[o]) { case "+": expr = expr + num; break; case "-": expr = expr - num; break; case "*": expr = expr * num; break; case "/": expr = expr / num; break; } } return expr; } 

我为了同样的目的创build了BigEval 。
在求解expression式时,它的执行与Eval()完全相同,并支持像%,^,&,**(power)这样的运算符和! (阶乘)。 你也可以在expression式中使用函数和常量(或者说variables)。 该expression式是以包括JavaScript在内的编程语言常见的PEMDAS顺序解决的。

 var Obj = new BigEval(); var result = Obj.exec("5! + 6.6e3 * (PI + E)"); // 38795.17158152233 var result2 = Obj.exec("sin(45 * deg)**2 + cos(pi / 4)**2"); // 1 var result3 = Obj.exec("0 & -7 ^ -7 - 0%1 + 6%2"); //-7 

如果你用任意精度处理数字,也可以使用这些大数字库进行算术运算。

我最终走了这个解决scheme,这是正负整数求和的工具(对正则expression式的一些修改也可以用于小数):

 function sum(string) { return (string.match(/^(-?\d+)(\+-?\d+)*$/)) ? string.split('+').stringSum() : NaN; } Array.prototype.stringSum = function() { var sum = 0; for(var k=0, kl=this.length;k<kl;k++) { sum += +this[k]; } return sum; } 

我不知道它是否比eval()更快,但是由于我必须执行很多次操作,所以比起创buildJavaScript编译器实例的负载,我更愿意运行这个脚本

尝试nerdamer

 var result = nerdamer('12+2+PI').evaluate(); document.getElementById('text').innerHTML = result.text(); 
 <script src="js/nerdamer.core.js"></script> <div id="text"></div> 

@kennebec的优秀答案的替代scheme,使用较短的正则expression式,并允许运算符之间的空格

 function addbits(s) { var total = 0; s = s.replace(/\s/g, '').match(/[+\-]?([0-9\.\s]+)/g) || []; while(s.length) total += parseFloat(s.shift()); return total; } 

像使用它

 addbits('5 + 30 - 25.1 + 11'); 

更新

这是一个更优化的版本

 function addbits(s) { return (s.replace(/\s/g, '').match(/[+\-]?([0-9\.]+)/g) || []) .reduce(function(sum, value) { return parseFloat(sum) + parseFloat(value); }); } 

尝试AutoCalculator https://github.com/JavscriptLab/autocalculate计算input值和输出通过使用select器expression式;

只需要为输出input添加一个属性,例如data-ac =“(#firstinput +#secondinput)”

不需要任何初始化只需添加data-ac属性。 它会自动找出dynamic添加的元素

用输出添加'R'只需在大括号内添加data-ac =“{Rs}(#firstinput +#secondinput)”

我相信parseIntES6可以在这种情况下有所帮助

==>这样:

 let func = (str) => { let arr = str.split(""); return `${Number(arr[0]) + parseInt(arr[1] + Number(arr[2]))}`}; console.log(func("1+1")); 

这里最主要的是parseInt用操作符parsing数字。 代码可以修改为相应的需要。