如何解析和计算字符串中的数学表达式(例如'1+1'
),而不使用 eval(string)
来返回其数值?
以该示例为例,我想让函数接受'1+1'
并返回2
。
如何解析和计算字符串中的数学表达式(例如'1+1'
),而不使用 eval(string)
来返回其数值?
以该示例为例,我想让函数接受'1+1'
并返回2
。
Parser.evaluate("2 ^ x", { x: 3 });
或者mathjs,它允许使用如下的功能:
math.eval('sin(45 deg) ^ 2');
我最终选择了mathjs作为我的一个项目。
使用 Function()
简单而优雅
function parse(str) {
return Function(`'use strict'; return (${str})`)()
}
document.write( "1+2+3", '=' , parse("1+2+3"), '<br>');
document.write( "1 + 2 * 3", '=' , parse("1 + 2 * 3"), '<br>');
注意:不要在生产环境中使用
parse('process.exit()')
的出现。 - Bastiparse('alert("hello")')
。 - thibpat你可以轻松地执行加号或减号操作:
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';
console.log(
addbits(string)
)
更加复杂的数学使得 eval 更具吸引力 - 且写起来肯定更简单。
需要有人来解析这个字符串。如果不是解释器(通过eval
),那么就需要你编写一个解析程序来提取数值、运算符和任何其他你想在数学表达式中支持的内容。
因此,没有(简单的)方法可以不使用eval
。如果你担心安全性(因为你解析的输入不是来自你控制的源),也许你可以在将其传递给eval
之前检查输入的格式(通过白名单正则表达式过滤器)?
作为对@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;
}
使用方法如下:
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);
});
}
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
如果你需要处理任意精度的数字,也可以使用大数库进行算术计算。
我正在寻找用于计算数学表达式的JavaScript库,并找到了这两个有前途的候选者:
JavaScript表达式求值器:更小,希望更轻量级。允许代数表达式、替换和一些函数。
mathjs:还允许使用复数、矩阵和单位。专为在浏览器JavaScript和Node.js中使用而构建。
/**
* 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;
}
1+2*3
应该返回 7,而不是 9。 - tanguy_kEval()
...)通过在逆波兰表达式中评估表达式(这是容易的部分)。难点实际上是解析字符串并将其转换为逆波兰表达式。我使用了Shunting Yard算法,因为维基百科和伪代码上有一个很好的例子。我发现两者都很容易实现,并且如果您还没有找到解决方案或正在寻找替代方案,我建议使用它们。eval("2++")
这样的错误。
function evaluateMath(str) {
for (var i = 0; i < str.length; i++) {
if (isNaN(str[i]) && !['+', '-', '/', '*', '%', '**'].includes(str[i])) {
return NaN;
}
}
try {
return eval(str)
} catch (e) {
if (e.name !== 'SyntaxError') throw e
return NaN;
}
}
console.log(evaluateMath('2 + 6'))
或者你可以使用Math.eval
来代替函数。
Math.eval = function(str) {
for (var i = 0; i < str.length; i++) {
if (isNaN(str[i]) && !['+', '-', '/', '*', '%', '**'].includes(str[i])) {
return NaN;
}
}
try {
return eval(str)
} catch (e) {
if (e.name !== 'SyntaxError') throw e
return NaN;
}
}
console.log(Math.eval('2 + 6'))
(Function("return 1+1;"))()
。 (注:该代码为JavaScript语言,执行结果为2。) - Gumbo