0

good day.

I have to parse some arithmetic operations like:

A + b * 0.75 + 3

and (c-Ff)-1/2

I need to put separate elements in groups.

So I need to have parsed

let var1 = 'A';
let operator1 = '+';
let var2 = 'b';
let operator2 = '*';
let var3 = 0.75;
let operator3 = '+';
let var4 = 3;

So I can match my A variable with mine pre-defined variable and made some calculations.

I have ended with [^+/*()-]+ but it

  1. captures spaces
  2. doesn't put +-/* in separate groups
  3. i dunno how to handle brackets

Any advices, please?

deathfry
  • 626
  • 1
  • 7
  • 28

1 Answers1

1

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

Peter Thoeny
  • 7,379
  • 1
  • 10
  • 20