In Javascript how to evaluate expressions if there are other text too

Viewed 291

I have the following string in javascript

var q = "M (95+(4*5)) L (95-(4*5))"

I need it to look like

"M 115 L 75"

Please note that var q could be a very long pattern with multiple M and L. Would anybody know how to accomplish this. Any help will be greatly appreciated.

5 Answers

Here's a sane and reliable way to do it, without resorting to eval:

var q = "M (95+(4*5)) L (95.3-(4*5))"

let res = (function fix(input){
  let output = input.replace(/\(\s*(-?[\d.]+)\s*([*+-])\s*(-?[\d.]+)\s*\)/g, function(_, a, op, b){
     switch(op){
     case '+': return +a + +b;
     case '-': return a - b;
     case '*': return a * b;
     default: return "_";
     }
   });
   return input==output ? input : fix(output);
})(q);

console.log("res=", res);

The idea is simply to replace all ( number operator number ) until there's nothing to replace.

Note that this would also work for more complex expressions (I assume you're building a SVG path) and wouldn't break at the first added space.

You could take M and L as marker and take only the part between for eval.

var q = "M (95+(4*5)) L (95-(4*5))";

q = q.replace(/([ML])(.*?)(?=[ML]|$)/g, (_, a, b) => a + ' ' + eval(b) +' ');

console.log(q);

You need fix parenthesis

  let str = "M (95+(4*5)) L (95-(4*5))";
  
  let res = str.split(" ").map(e=>{
    try{
      return eval(e);
    }catch(err){
      return e;
    }
  }).join(" ");
  
  console.log(res)

If the initial string is always formated in this way i would split then eval when the element is not a reserved char

var q = 'M (95+(4*5)) L (95-(4*5))'

let processed = ''
let arr = q.split(' ')

arr.forEach(a => {
  if (a !== 'M' && a !== 'L') {
    a = eval(a)
  }
  processed = processed.concat(a, ' ')
})
# Now proccessed is 'M 115 L 75 ' you can trim and remove extra space
processed = processed.trim()

I don't recommend using this if you will be using this on client-side, because as others said this can be changed via F12.

But if you will be using this only at server-side with controlled inputs, then it's not a problem.

Edit: For future readers: My solution was downvoted by users that think that using eval() is a security risk. And they are correct that evaluating untrusted code, is a risk. But since OP didn't said anything about the source beeing untrusted, my solution is still valid until OP clarifies that the string-source is indeed untrusted.

The solution, in my opinion, is a 2-way solution:

First, use regular expressions to group the string into one letter (like "M") and the rest until the next letter.

You may also use an easier approach by string-splitting at the letters (like "M" and "L").

Regardless of which way you choose, you get an array of objects with each entry having a letter and some math-string.

You can simply eval() the math-sting (https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/eval) and get the result.

This is not too hard in my opinion but it's some nice way to get into string-splitting and "eval" :)

Related