Evaluating a string as a mathematical expression in JavaScript
Solution 1
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
Solution 2
You can use the JavaScript Expression Evaluator library, which allows you to do stuff like:
Parser.evaluate("2 ^ x", { x: 3 });
Or mathjs, which allows stuff like:
math.eval('sin(45 deg) ^ 2');
I ended up choosing mathjs for one of my projects.
Solution 3
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';
console.log(
addbits(string)
)
More complicated math makes eval more attractive- and certainly simpler to write.
Solution 4
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.
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
?
Solution 5
An alternative to the excellent answer by @kennebec, using a shorter regular expression and allowing spaces between operators
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);
});
}
wheresrhys
Mostly a front-end developer, working with html, css and recently nursing an addiction to jQuery/javascript too. Also delving a bit into php development using the zend framework. I play in an irish folk band, go birdwatching, and enjoy listening to classic reggae.
Updated on September 29, 2021Comments
-
wheresrhys over 2 years
How do I parse and evaluate a mathematical expression in a string (e.g.
'1+1'
) without invokingeval(string)
to yield its numerical value?With that example, I want the function to accept
'1+1'
and return2
.