Safe evaluation of arithmetic expressions in Javascript
I need to evaluate user-entered arithmetic expressions like "2 * (3 + 4)" in Javascript but I don't want to use eval
for security reasons.
I could strip out all the characters that are not numbers or operators but I'm not sure this would be safe anyway and it would be nice if the user could use functions like cos
, sqrt
, etc...
Are there any Javascript libraries that do arithmetic expression evaluation?
Solution 1:
you can try JavaScript Expression Evaluator:
This library is a modified version of Raphael Graf’s ActionScript Expression Parser. When I wrote the JavaScript Function Plotter, I wanted a better alternative to using JavaScript’s eval function. There’s no security risk currently, because you can only run code in your own browser, but it’s not as convenient for math (Math.pow(2^x) instead of 2^x, etc.).
then your code will be like that:
console.info ( Parser.evaluate( "2 * (3 + 4)" ) ); //prints 14
Solution 2:
As already mentioned, the most damage any user could do is pretty much what they could already do using the built-in console in any of the major browsers. However, if you wanted to restrict the user to using Math
properties/methods, you could write a simple regex to handle this for you. Something like this should work:
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"); };
}
I realize you didn't want to use eval
for security reasons, but the regex should make it pretty safe as it rules out any words that aren't direct properties of the Math
object and most non-math JS operators, including the assignment operator (=
) and binary operators. The harder method would be writing a tokenizer to parse the mathematical expression, because it's not a regular language.
Feel free to try and break the working example I wrote, if you can or if you notice a problem, leave a comment and I'll see what I can do to fix it.
Note: Yi Jiang mentioned [in JavaScript chat](https://chat.stackoverflow.com/rooms/17/javascript) that it might also be useful to allow lower case for things like `Math.PI`. If that's the case, you could just add the following `else if` statement in the replacement function:
else if (Math.hasOwnProperty($0.toUpperCase())
return "Math."+$0.toUpperCase();
Add it between the if
and else
statement (example).