Ok, here are two attempts at parsing your sample expressions:
function parseStringA(str) {
var vars = []; // numerical constants, symbolic names
var ops = []; // mathematical operators
str
.replace(/([\+\-\*\/\(\)])/g, ' $1 ') // force spaces arount ops
.split(/ +/) // split on spaces
.filter(Boolean) // remove empty items
.forEach(function(item) {
if(item.match(/[\+\-\*\/\(\)]/)) {
ops.push(item);
} else {
vars.push(item);
}
});
return {
vars: vars,
ops: ops
}
}
function parseStringB(str) {
var expr = []; // { val, op }
str
.replace(/([\+\-\*\/\(\)])/g, ' $1 ') // force spaces arount ops
.split(/ +/) // split on spaces
.filter(Boolean) // remove empty items
.forEach(function(item) {
if(item.match(/[\+\-\*\/\(\)]/)) {
expr.push({ val: '', op: item});
} else {
expr.push({ val: item, op: ''});
}
});
return expr;
}
var str1 = 'A + b * 0.75 + 3';
var str2 = '(c-Ff)-1/2';
var result1a = parseStringA(str1);
console.log('result1a: ' + JSON.stringify(result1a, null, ' '))
var result2a = parseStringA(str2);
console.log('result2a: ' + JSON.stringify(result2a, null, ' '))
var result1b = parseStringB(str1);
console.log('result1b: ' + JSON.stringify(result1b, null, ' '))
var result1b = parseStringB(str2);
console.log('result1b: ' + JSON.stringify(result1b, null, ' '))
Function parseStringA()
splits the expression into (numerical constants / symbolic names) and mathematical operators, as per your original example. The result is not useful because you lose the sequence of items in the expression, as you can see from the output:
result1a: {
"vars": [
"A",
"b",
"0.75",
"3"
],
"ops": [
"+",
"*",
"+"
]
}
result2a: {
"vars": [
"c",
"Ff",
"1",
"2"
],
"ops": [
"(",
"-",
")",
"-",
"/"
]
}
A better approach is function parseStringB()
, which returns an array of objects with val
(numerical constants / symbolic names) and op
(mathematical operators). Here is the output:
result1b: [
{ "val": "A", "op": "" },
{ "val": "", "op": "+" },
{ "val": "b", "op": "" },
{ "val": "", "op": "*" },
{ "val": "0.75", "op": "" },
{ "val": "", "op": "+" },
{ "val": "3", "op": "" }
]
result1b: [
{ "val": "", "op": "(" },
{ "val": "c", "op": "" },
{ "val": "", "op": "-" },
{ "val": "Ff", "op": "" },
{ "val": "", "op": ")" },
{ "val": "", "op": "-" },
{ "val": "1", "op": "" },
{ "val": "", "op": "/" },
{ "val": "2", "op": "" }
]
This format is more useful. Now you can iterate over the array to resolve the expression, which appears to be out of scope of your question.
This is the first step of evaluating an expression, called tokenizing - the array contains the tokens. The next step is to create a parse tree so that you can properly evaluate parenthesis inside-out, multiplication before addition, etc.
This blog has a good overview: https://blog.bitsrc.io/parsing-expressions-in-javascript-4c156f0cbaec