const thatString = ' 10 + 33.1 + 2 3 3 * 0 22 % 45 + 10 + 3 2 1 + 2 3 3 + 0 22 - 45 + 10 + 3 2 1 * 22.3 + 0 22 - 45 / 10 + 3 2 1 + 2 3 3 % 0 22 - 45 / 10 + 3 2 1 + 2 3 3 + 0 22 * 45 ';
const thatStringOnlyAddSubstr = ' 10 + 3 2 1 + 2 3 3 + 0 22 - 45 + 10 + 3 2 1 + 2 3 3 + 0 22 - 45 + 10 + 3 2 1 + 2 3 3 + 0 22 - 45 + 10 + 3 2 1 + 2 3 3 + 0 22 - 45 + 10 + 3 2 1 + 2 3 3 + 0 22 - 45 ';
function calcMe(str) {
const noWsStr = str.replace(/\s/g, '');
const operators = noWsStr.replace(/[\d.,]/g, '').split('');
const operands = noWsStr.replace(/[+/%*-]/g, ' ')
.replace(/\,/g, '.').split(' ')
.map(parseFloat)
.filter(it => it);
if (operators.length >= operands.length){
throw new Error('Operators qty must me lesser than operands qty')
};
while (operators.includes('*')) {
let opIndex = operators.indexOf('*');
operands.splice(opIndex, 2, operands[opIndex] * operands[opIndex + 1]);
operators.splice(opIndex, 1);
};
while (operators.includes('/')) {
let opIndex = operators.indexOf('/');
operands.splice(opIndex, 2, operands[opIndex] / operands[opIndex + 1]);
operators.splice(opIndex, 1);
};
while (operators.includes('%')) {
let opIndex = operators.indexOf('%');
operands.splice(opIndex, 2, operands[opIndex] % operands[opIndex + 1]);
operators.splice(opIndex, 1);
};
let result = operands[0];
for (let i = 0; i < operators.length; i++) {
operators[i] === '+' ? (result += operands[i + 1]) : (result -= operands[i + 1])
}
return result
}
// Does not support braces
calcMe(thatString)
calcMe(thatStringOnlyAddSubstr)
calculate(thatString)
function calculate(input) {
var f = {
add: '+',
sub: '-',
div: '/',
mlt: '*',
mod: '%',
exp: '^'
};
// Create array for Order of Operation and precedence
f.ooo = [
[
[f.mlt],
[f.div],
[f.mod],
[f.exp]
],
[
[f.add],
[f.sub]
]
];
input = input.replace(/[^0-9%^*\/()\-+.]/g, ''); // clean up unnecessary characters
var output;
for (var i = 0, n = f.ooo.length; i < n; i++) {
// Regular Expression to look for operators between floating numbers or integers
var re = new RegExp('(\\d+\\.?\\d*)([\\' + f.ooo[i].join('\\') + '])(\\d+\\.?\\d*)');
re.lastIndex = 0; // take precautions and reset re starting pos
// Loop while there is still calculation for level of precedence
while (re.test(input)) {
output = _calculate(RegExp.$1, RegExp.$2, RegExp.$3);
if (isNaN(output) || !isFinite(output))
return output; // exit early if not a number
input = input.replace(re, output);
}
}
return output;
function _calculate(a, op, b) {
a = a * 1;
b = b * 1;
switch (op) {
case f.add:
return a + b;
break;
case f.sub:
return a - b;
break;
case f.div:
return a / b;
break;
case f.mlt:
return a * b;
break;
case f.mod:
return a % b;
break;
case f.exp:
return Math.pow(a, b);
break;
default:
null;
}
}
}
//------ALSO
//1) not so safe (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function)
//function evil(fn) {
//return new Function('return ' + fn.replace(/\s/g,''))();
//}
//evil(thatString)
// 2) totally not safe
// eval('10 + 3 % 21 + 2 * 330 *2/2 - 45')