How do I parse and evaluate a mathematical expression in a string (e.g. \'1+1\'
) without invoking eval(string)
to yield its numerical value?
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.
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.
Try AutoCalculator https://github.com/JavscriptLab/autocalculate Calculate Inputs value and Output By using selector expressions
Just add an attribute for your output input like data-ac="(#firstinput+#secondinput)"
No Need of any initialization just add data-ac attribute only. It will find out dynamically added elements automatically
FOr add 'Rs' with Output just add inside curly bracket data-ac="{Rs}(#firstinput+#secondinput)"
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);
});
}
This is a little function I threw together just now to solve this issue - it builds the expression by analyzing the string one character at a time (it's actually pretty quick though). This will take any mathematical expression (limited to +,-,*,/ operators only) and return the result. It can handle negative values and unlimited number operations as well.
The only "to do" left is to make sure it calculates * & / before + & -. Will add that functionality later, but for now this does what I need...
/**
* 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;
}
You could use a for loop to check if the string contains any invalid characters and then use a try...catch with eval to check if the calculation throws an error like eval("2++")
would.
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'))
or instead of a function, you could set 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'))