2

I wanted to replace integers in my string formula to evaluate the expression.

I have an array such as

var value_array=[
{value: "11", order: "1"},
{value: "4", order: "2"},
{value: "31", order: "3"},
{value: "41", order: "4"},
{value: "51", order: "5"},
{value: "61", order: "6"},
{value: "71", order: "7"},
{value: "80", order: "8"},
{value: "91", order: "9"},
{value: "101", order: "10"},
{value: "111", order: "11"},
{value: "128", order: "12"},
{value: "131", order: "13"},
{value: "145", order: "14"}
];

and my formula is ((1+14)*5+12*3-7*8/2+4)

I wanted to replace integers with corresponding order value.

I should get ((11+145)*51+128*31-71*80/4+41), then I will evaluate the string which resulted from 10545.

Thanks for your help

Gufran Hasan
  • 8,910
  • 7
  • 38
  • 51
alperzzz
  • 53
  • 5
  • @xianshenglu's answer worked fine on jsfiddle but my platform does not support es6, do you have any suggestions? – alperzzz May 16 '18 at 14:30

5 Answers5

5

try replace and find:

let str = `((1+14)*5+12*3-7*8/2+4)`
let value_array = [
  { value: '11', order: '1' },
  { value: '4', order: '2' },
  { value: '31', order: '3' },
  { value: '41', order: '4' },
  { value: '51', order: '5' },
  { value: '61', order: '6' },
  { value: '71', order: '7' },
  { value: '80', order: '8' },
  { value: '91', order: '9' },
  { value: '101', order: '10' },
  { value: '111', order: '11' },
  { value: '128', order: '12' },
  { value: '131', order: '13' },
  { value: '145', order: '14' }
]
let res = str.replace(/([^\d]*?)(\d+)([^\d]*?)/g, (...args) => {
  return args[1] + value_array.find(o => o.order === args[2]).value + args[3]
})
console.log(res)

here is es5 version transformed by babel

var str = '((1+14)*5+12*3-7*8/2+4)';
var value_array = [{ value: '11', order: '1' }, { value: '4', order: '2' }, { value: '31', order: '3' }, { value: '41', order: '4' }, { value: '51', order: '5' }, { value: '61', order: '6' }, { value: '71', order: '7' }, { value: '80', order: '8' }, { value: '91', order: '9' }, { value: '101', order: '10' }, { value: '111', order: '11' }, { value: '128', order: '12' }, { value: '131', order: '13' }, { value: '145', order: '14' }];
var res = str.replace(/([^\d]*?)(\d+)([^\d]*?)/g, function () {
  for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
    args[_key] = arguments[_key];
  }

  return args[1] + value_array.find(function (o) {
    return o.order === args[2];
  }).value + args[3];
});
console.log(res);
xianshenglu
  • 4,943
  • 3
  • 17
  • 34
  • 1
    you can use eval(res) to get the result. – Mohammad Ali Rony May 16 '18 at 09:19
  • 1
    @MohammadAliRony,yeah,I know that,but `eval` is not a good idea.That's why I didn't write it over.However,I didn't figure out another easier way to execute that formula. – xianshenglu May 16 '18 at 09:21
  • About how to get rid of eval - [here](https://stackoverflow.com/questions/6479236/calculate-string-value-in-javascript-not-using-eval) – Orelsanpls May 16 '18 at 09:25
  • Have you tried the code? It reports a syntax error. – axiac May 16 '18 at 09:27
  • @axiac,I tried,and if it reports a syntax error,i won't get 4 upvotes.I guess the problem is your network or browser doesn't support ES6? – xianshenglu May 16 '18 at 09:30
  • It's not about ES6. In Firefox, the error message is *"SyntaxError: invalid regular expression flag s"*. This is the list of flags it supports: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced%20searching%20with%20flags And since Google, Microsoft and Mozilla agreed several months ago to store the documentation of web technologies on [MDN](https://developer.mozilla.org/en-US/), I would use this documentation as reference. – axiac May 16 '18 at 09:33
  • @axiac,`s` is a new flag which belongs to ES7 or ES8 .It can match line break.You can try this in chrome` `line break starts end`.match(/./gs);/*I got 22,including the line break*/` ` – xianshenglu May 16 '18 at 09:39
  • I know what `s` does and it is useless in the `regex` posted in the answer. – axiac May 16 '18 at 09:44
  • @axiac,okay,I just removed the `s` flag.I use it for more safe just like `u` flag – xianshenglu May 16 '18 at 09:46
  • It doesn't need `u` either. All it cares are the digits of the Latin alphabet. – axiac May 16 '18 at 09:47
  • thanks for the answer, it worked on jsfiddle but my platform does not support es6, do you have any suggestions? – alperzzz May 16 '18 at 13:13
  • 1
    @alperzzz updated the answer.Remember that es6 can be transformed to es5 by [babel](https://babeljs.io/repl/#) – xianshenglu May 17 '18 at 01:13
1

You can try following (generic solutions)

With while loop

var value_array=[{value: "11", order: "1"},{value: "4", order: "2"},{value: "31", order: "3"},{value: "41", order: "4"},{value: "51", order: "5"},{value: "61", order: "6"},{value: "71", order: "7"},{value: "80", order: "8"},{value: "91", order: "9"},{value: "101", order: "10"},{value: "111", order: "11"},{value: "128", order: "12"},{value: "131", order: "13"},{value: "145", order: "14"}]

// Formula that needs to be evaluated
var formula = "((1+14)*5+12*3-7*8/2+4)";

// Create the map for order value pair
var map = {};
value_array.forEach(({order, value}) => map[order] = value);

var formulaArray = formula.split('');
var i = 0;
var num = "";
var result = "";

// Iterate over character array and replace order with values from map
while (i < formulaArray.length) {
  if (isNaN(formulaArray[i])) {
    if (num) {
      result += map[num];
      num = "";
    }
    result += formulaArray[i];
  } else {
    num += formulaArray[i];
  }
  i++;
}

// In case there is a number at last and not added in result
if (num) {
  result += map[num];
}

// Finally evaluating the result
console.log(eval(result));

With match and replace

var value_array=[{value: "11", order: "1"},{value: "4", order: "2"},{value: "31", order: "3"},{value: "41", order: "4"},{value: "51", order: "5"},{value: "61", order: "6"},{value: "71", order: "7"},{value: "80", order: "8"},{value: "91", order: "9"},{value: "101", order: "10"},{value: "111", order: "11"},{value: "128", order: "12"},{value: "131", order: "13"},{value: "145", order: "14"}]

// Formula that needs to be evaluated
var formula = "((1+14)*5+12*3-7*8/2+4)";
// Collect all the orders
var orders = formula.match(/\d+/g);
// replace all orders with special character
formula = formula.replace(/\d+/g, "~~");

// iterate over orders and replace the order with value from value_array
orders.forEach((order, index) => {
  var value = value_array.find((val) => val.order === order);
  orders[index] = value.value; // assuming value will always be found
});

// Iterating over the orders and replacing each special character with the value stored in orders array
orders.forEach((val) => {
  formula = formula.replace("~~", val);
});

// Finally evaluating the formula
console.log(eval(formula));
Nikhil Aggarwal
  • 28,197
  • 4
  • 43
  • 59
0

You can iterate through the array and parse corresponding fields. Here how you can do it:

    
var value_array=[{value: "11", order: "1"},{value: "4", order: "2"},{value: "31", order: "3"},{value: "41", order: "4"},{value: "51", order: "5"},{value: "61", order: "6"},{value: "71", order: "7"},{value: "80", order: "8"},{value: "91", order: "9"},{value: "101", order: "10"},{value: "111", order: "11"},{value: "128", order: "12"},{value: "131", order: "13"},{value: "145", order: "14"}]

value_array.forEach(elem =>{
  elem.order = parseInt(elem.order);
});

console.log(value_array);

    
snnsnn
  • 10,486
  • 4
  • 39
  • 44
0

You can create a function which is gonna do the replace.

const value_array = [{
  value: "11",
  order: "1",
}, {
  value: "4",
  order: "2",
}, {
  value: "31",
  order: "3",
}, {
  value: "41",
  order: "4",
}, {
  value: "51",
  order: "5",
}, {
  value: "61",
  order: "6",
}, {
  value: "71",
  order: "7",
}, {
  value: "80",
  order: "8",
}, {
  value: "91",
  order: "9",
}, {
  value: "101",
  order: "10",
}, {
  value: "111",
  order: "11",
}, {
  value: "128",
  order: "12",
}, {
  value: "131",
  order: "13",
}, {
  value: "145",
  order: "14",
}];

// Function that's gonna replace the order with the value
function rbo(order) {
  const ret = value_array.find(x => x.order === String(order));

  if (!ret) {
    throw new Error('Cannot proceed', order);
  }

  return Number(ret.value);
}

const formulaResult = ((rbo(1) + rbo(14)) * rbo(5) + rbo(12) * rbo(3) - rbo(7) * rbo(8) / rbo(2) + rbo(4));

console.log(formulaResult);

You can simplify the data array tho

const value_array = [11, 4, 31, 41, 51, 61, 71, 80, 91, 101, 111, 128, 131, 145];

// Function that's gonna replace the order with the value
function rbo(order) {
  if (typeof value_array[order - 1] === 'undefined') {
    throw new Error(`Cannot proceed ${order}`);
  }

  return value_array[order - 1];
}

const formulaResult = ((rbo(1) + rbo(14)) * rbo(5) + rbo(12) * rbo(3) - rbo(7) * rbo(8) / rbo(2) + rbo(4));

console.log(formulaResult);
Orelsanpls
  • 22,456
  • 6
  • 42
  • 69
0

You could use a hash table for replacing all numbers.

var values = [{ value: "11", order: "1" }, { value: "4", order: "2" }, { value: "31", order: "3" }, { value: "41", order: "4" }, { value: "51", order: "5" }, { value: "61", order: "6" }, { value: "71", order: "7" }, { value: "80", order: "8" }, { value: "91", order: "9" }, { value: "101", order: "10" }, { value: "111", order: "11" }, { value: "128", order: "12" }, { value: "131", order: "13" }, { value: "145", order: "14" }],
    hash = values.reduce((h, { value, order }) => Object.assign(h, { [order]: value }), Object.create(null)),
    formula = '((1+14)*5+12*3-7*8/2+4)';
    
formula = formula.replace(/\d+/g, m => m in hash ? hash[m]: m);

console.log(formula);
console.log(eval(formula));
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392