Safe Evaluation of Arithmetic Expressions in JavaScript

Safe evaluation of arithmetic expressions in Javascript

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

The source code is on GitHub and it's published on npm as expr-eval. Can be used like so:

import { Parser } from 'expr-eval';

console.log(Parser.evaluate("2 * (3 + 4)")); // 14

Evaluating a string as a mathematical expression in JavaScript

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

Evaluate an Equation in Javascript, without eval()

I only really know two alternatives, one is to use a script element that is dynamically written to the page, e.g.:

function evaluate(formula)
{
var script = document.createElement("script");
script.type = "text/javascript";
script.text = "window.__lr = " + formula + ";";
document.body.appendChild(script);
document.body.removeChild(script);

var r = window.__lr;

return r;
}

The other would be to use new Function(...):

function evaluate3(formula)
{
var func = new Function("return " + formula);
return func();
}

But I don't think you'll find something that yields similar performance to eval: http://jsperf.com/alternative-evaluation

The performance of eval varies across browsers and platforms, have you got a specific browser/platform combination in mind? The newer javascript engines in improved browsers will offer optimised eval:

Test Results

This is only a limited set of tests on a few UAs, but it should give you an idea of how it performs in different environments.

How do I check if a given string from a user is a valid arithmetic equation?

I'd set up a function that checks for the following:

  • Invalid pairs of adjacent characters, such as *^, -), and +/, while allowing other unspecified combinations (such as ((,--,+(-()
  • Incorrect parentheses, whether that be the incorrect number of open vs close, or closing parentheses with no corresponding opening ones.
  • Non-numeric or infinite (Infinity keyword) values between specified, allowable operators

document.querySelector("input").addEventListener("keyup", function() {  document.getElementById("output").innerHTML = isValid(this.value);});
function isValid(str) { var invalidOperatorPairs = ["**", "*/", "/*", "//", "()", "^^", "^/", "/^", "^*", "*^", "-)", "+)", "*)", "/*", "^)", "-*", "-/", "-^", "+*", "+/", "+^", "(*", "(/", "(^","/)","*)","+)","-)","^)"] str = "(" + str + ")"; var open = 0; for (var i = 0, len = str.length; i < len; i++) { var curr = str[i]; if (curr === "(") { open += 1; } else if (curr === ")") { open -= 1; if (open < 0) { return false } } if (i > 0) { for (var j = 0, oplen = invalidOperatorPairs.length; j < oplen; j++) { if (str[i - 1] == invalidOperatorPairs[j][0] && curr == invalidOperatorPairs[j][1]) { return false } } } } if (open !== 0) return false; var sections = str.split(/[\+\-\*\/\^\)\(]/g); for (i = 0, len = sections.length; i < len; i++) { if ((sections[i].length > 0) && !(Number(sections[i]) !== NaN && isFinite(sections[i]))) { return false } } return true;}
<input type="text" value="" /><div id="output"></div>


Related Topics



Leave a reply



Submit