在 JavaScript 中将字符串计算为数学表达式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2276021/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Evaluating a string as a mathematical expression in JavaScript
提问by wheresrhys
How do I parse and evaluate a mathematical expression in a string (e.g. '1+1') without invoking eval(string)to yield its numerical value?
如何解析和评估字符串(例如'1+1')中的数学表达式而不调用eval(string)产生其数值?
With that example, I want the function to accept '1+1'and return 2.
在那个例子中,我希望函数接受'1+1'并返回2.
采纳答案by wheresrhys
I've eventually gone for this solution, which works for summing positive and negative integers (and with a little modification to the regex will work for decimals too):
我最终选择了这个解决方案,它适用于对正整数和负整数求和(对正则表达式稍加修改也适用于小数):
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;
}
I'm not sure if it's faster than eval(), but as I have to carry out the operation lots of times I'm far more comfortable runing this script than creating loads of instances of the javascript compiler
我不确定它是否比 eval() 快,但是由于我必须多次执行该操作,因此运行此脚本比创建大量 javascript 编译器实例要舒服得多
回答by Rafael Vega
You can use the JavaScript Expression Evaluator library, which allows you to do stuff like:
您可以使用JavaScript Expression Evaluator library,它允许您执行以下操作:
Parser.evaluate("2 ^ x", { x: 3 });
Or mathjs, which allows stuff like:
或mathjs,它允许以下内容:
math.eval('sin(45 deg) ^ 2');
I ended up choosing mathjs for one of my projects.
我最终为我的一个项目选择了 mathjs。
回答by kennebec
// You can do + or - easily:
// 您可以轻松地执行 + 或 - 操作:
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)
More complicated math makes eval more attractive- and certainly simpler to write.
更复杂的数学使 eval 更具吸引力——当然也更容易编写。
回答by bdukes
Somebody has to parse that string. If it's not the interpreter (via eval) then it'll need to be you, writing a parsing routine to extract numbers, operators, and anything else you want to support in a mathematical expression.
有人必须解析该字符串。如果它不是解释器(通过eval),那么它需要是你,编写一个解析例程来提取数字、运算符和任何你想要在数学表达式中支持的东西。
So, no, there isn't any (simple) way without eval. If you're concerned about security (because the input you're parsing isn't from a source you control), maybe you can check the input's format (via a whitelist regex filter) before passing it to eval?
所以,不,没有任何(简单)方法没有eval. 如果您担心安全性(因为您解析的输入不是来自您控制的源),也许您可以在将输入的格式(通过白名单正则表达式过滤器)传递给eval?
回答by Stefan Gabos
An alternative to the excellent answer by @kennebec, using a shorter regular expression and allowing spaces between operators
@kennebec 出色答案的替代方法,使用较短的正则表达式并允许运算符之间有空格
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;
}
Use it like
使用它就像
addbits('5 + 30 - 25.1 + 11');
Update
更新
Here's a more optimised version
这是一个更优化的版本
function addbits(s) {
return (s.replace(/\s/g, '').match(/[+\-]?([0-9\.]+)/g) || [])
.reduce(function(sum, value) {
return parseFloat(sum) + parseFloat(value);
});
}
回答by Avi
I created BigEvalfor the same purpose.
In solving expressions, it performs exactly same as Eval()and supports operators like %, ^, &, ** (power) and ! (factorial).
You are also allowed to use functions and constants (or say variables) inside the expression. The expression is solved in PEMDAS orderwhich is common in programming languages including JavaScript.
我出于同样的目的创建了BigEval。
在求解表达式时,它的性能与Eval()%、^、&、**(幂)和 ! 等运算符完全相同并支持。(阶乘)。您还可以在表达式中使用函数和常量(或说变量)。该表达式以PEMDAS 顺序求解,这在包括 JavaScript 在内的编程语言中很常见。
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
It can also be made to use those Big Number libraries for arithmetic in case you are dealing with numbers with arbitrary precision.
如果您处理具有任意精度的数字,也可以使用这些 Big Number 库进行算术运算。
回答by Itangalo
I went looking for JavaScript libraries for evaluating mathematical expressions, and found these two promising candidates:
我去寻找用于评估数学表达式的 JavaScript 库,并找到了这两个有前途的候选者:
JavaScript Expression Evaluator: Smaller and hopefully more light-weight. Allows algebraic expressions, substitutions and a number of functions.
mathjs: Allows complex numbers, matrices and units as well. Built to be used by both in-browser JavaScript and Node.js.
JavaScript 表达式评估器:更小,希望更轻量级。允许代数表达式、替换和许多函数。
mathjs:也允许复数、矩阵和单位。专为浏览器内 JavaScript 和 Node.js 使用而构建。
回答by RichK
I've recently done this in C# (no Eval() for us...) by evaluating the expression in Reverse Polish Notation (that's the easy bit). The hard part is actually parsing ths string and turning it into Reverse Polish Notation. I used the Shunting Yard algorithm as there's a great example on Wikipedia and pseudocode. I found it really simple to implement both and I'd recommend that if you've not already found a solution or are looking at alternatives.
我最近在 C# 中完成了这个(我们没有 Eval() ......),通过评估反向波兰表示法中的表达式(这是简单的一点)。困难的部分实际上是解析字符串并将其转换为反向波兰表示法。我使用了 Shunting Yard 算法,因为维基百科和伪代码上有一个很好的例子。我发现实现这两者非常简单,如果您还没有找到解决方案或正在寻找替代方案,我建议您这样做。
回答by jMichael
This is a little function I threw together just now to solve this issue - it builds the expression by analyzing the string one character at a time (it's actually pretty quick though). This will take any mathematical expression (limited to +,-,*,/ operators only) and return the result. It can handle negative values and unlimited number operations as well.
这是我刚刚拼凑起来的一个小函数来解决这个问题 - 它通过一次分析一个字符的字符串来构建表达式(虽然它实际上非常快)。这将采用任何数学表达式(仅限于 +、-、*、/ 运算符)并返回结果。它也可以处理负值和无限数量的操作。
The only "to do" left is to make sure it calculates * & / before + & -. Will add that functionality later, but for now this does what I need...
剩下的唯一“要做”就是确保它在 + & - 之前计算 * & /。稍后会添加该功能,但现在这满足了我的需求......
/**
* 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;
}

