我需要在Javascript中评估用户输入的算术表达式,如“2 *(3 + 4)”,但出于安全原因,我不想使用eval
。
我可以删除所有不是数字或运算符的字符,但我不确定这是否安全如果用户可以使用cos
,sqrt
这样的函数会很好等等......
是否有任何Javascript库可以进行算术表达式求值?
答案 0 :(得分:20)
您可以尝试JavaScript Expression Evaluator:
这个库是修改后的版本 Raphael Graf的ActionScript表达 分析器。当我写JavaScript时 功能绘图仪,我想要更好 替代使用JavaScript的eval 功能即可。没有安全风险 目前,因为你只能跑 您自己的浏览器中的代码,但事实并非如此 方便数学(Math.pow(2 ^ x) 而不是2 ^ x等。)。
然后你的代码将是这样的:
console.info ( Parser.evaluate( "2 * (3 + 4)" ) ); //prints 14
答案 1 :(得分:9)
正如已经提到的,任何用户可以做的最大损害就是他们在任何主流浏览器中使用内置控制台已经可以做的事情。但是,如果您想限制用户使用Math
属性/方法,您可以编写一个简单的正则表达式来为您处理此问题。这样的事情应该有效:
function mathEval (exp) {
var reg = /(?:[a-z$_][a-z0-9$_]*)|(?:[;={}\[\]"'!&<>^\\?:])/ig,
valid = true;
// Detect valid JS identifier names and replace them
exp = exp.replace(reg, function ($0) {
// If the name is a direct member of Math, allow
if (Math.hasOwnProperty($0))
return "Math."+$0;
// Otherwise the expression is invalid
else
valid = false;
});
// Don't eval if our replace function flagged as invalid
if (!valid)
alert("Invalid arithmetic expression");
else
try { alert(eval(exp)); } catch (e) { alert("Invalid arithmetic expression"); };
}
我意识到你出于安全原因不想使用eval
,但正则表达式应该让它非常安全,因为它排除了任何不是 direct 属性的单词。 Math
对象和大多数非数学JS运算符,包括赋值运算符(=
)和二元运算符。更难的方法是编写一个tokenizer来解析数学表达式,因为它不是常规语言。
随意尝试打破我写的working example,如果可以,或者如果你发现问题,请留言,我会看看我能做些什么来解决它。
<小时/> 注:Yi Jiang提到in JavaScript chat,对
Math.PI
之类的内容允许使用小写也可能有用。如果是这种情况,您可以在替换函数中添加以下else if
语句:
else if (Math.hasOwnProperty($0.toUpperCase())
return "Math."+$0.toUpperCase();
在if
和else
声明(example)之间添加。
答案 2 :(得分:3)
您可以使用math.js中的高级表达式解析器,它不使用JavaScript的eval。
用法:
var ans = math.eval('2 * (3 + 4)');
或使用解析器(支持变量和函数赋值):
var parser = math.parser();
var ans = parser.eval('2 * (3 + 4)');
答案 3 :(得分:1)
您可以使用正则表达式替换除白名单之外的所有内容。但是由于javascript是在客户端上执行的(除非你正在运行AOL http服务器),任何可以修改输入的人都可以修改代码 - 所以你实际上并没有真正做到任何更多或者比现在更不安全。
答案 4 :(得分:1)
尝试nerdamer
var result = nerdamer('sqrt(4)+cos(1)-2').evaluate();
document.getElementById('text').innerHTML = result.text();
&#13;
<script src="http://nerdamer.com/js/nerdamer.core.js"></script>
<div id="text"></div>
&#13;