Reputation: 103
I want to process two objects.
obj1 array object having formulas.
obj2 having values. I want to process/calculate both objects to get result such that key present in obj1 becomes actual key in output and value get processed with formula. Did it with EVAL but don't want to use eval it.
Please suggest any other method to do the same.
const obj1 = [{ _id: '5 f467650890a7444d8d9ea5b', keyname: 'fTime',
PTag: '(FaultHrs*360)+(FaultMins*60)+FaultSecs', __v: 0 },
{ _id: '5 f467650890a7444d8d9ea5b', keyname: 'rTime',
PTag: '(RunHrs*360)+(RunMins*60)+RunSecs', __v: 0 }
]
const obj2 = { FaultHrs: 2, FaultMins: 0, FaultSecs: 49, RunHrs: 1, RunMins: 0, RunSecs: 0,}
const res = obj1.reduce((res, k) => {
// find out parameters in formula
const matches = k.PTag.match(/[a-zA-Z]+/g);
// substitute them with numbers
const newTag = matches.reduce((tag, m) => tag.replace(m, obj2[m] || 0), k.PTag);
// calculate result
res[k.keyname] = eval(newTag);
return res;
}, {});
console.log(res)
Upvotes: 3
Views: 117
Reputation: 30705
You could try using a module such as math.js, it includes an evaluate function which does not use eval under the hood (I believe an older version did).
There are still security risks, they are detailed in the math.js documentation math.js security, but they should be lower than using eval directly.
const obj1 = [{ _id: '5 f467650890a7444d8d9ea5b', keyname: 'fTime',
PTag: '(Fault_Hrs1*360)+(Fault_Mins1*60)+Fault_Secs1', __v: 0 },
{ _id: '5 f467650890a7444d8d9ea5b', keyname: 'rTime',
PTag: '(RunHrs*360)+(RunMins*60)+RunSecs', __v: 0 }
]
const obj2 = { Fault_Hrs1: 2, Fault_Mins1: 0, Fault_Secs1: 49, RunHrs: 1, RunMins: 0, RunSecs: 0,}
const res = obj1.reduce((res, k) => {
// find out parameters in formula
const matches = k.PTag.match(/([a-zA-Z]{1}[a-zA-Z0-9_]+)/g);
// substitute them with numbers
const newTag = matches.reduce((tag, m) => tag.replace(m, obj2[m] || 0), k.PTag);
// calculate result, using math.js evaluate function.
res[k.keyname] = math.evaluate(newTag);
return res;
}, {});
console.log(res)
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/7.2.0/math.js" integrity="sha512-O3GZu6Lz0va4Lk7IuF3CjKx5Jfxi35Gcx3oAjH7m7KRP5xvqorrInDpg3OFVJ6dMPn03vHiwgkgPT/hWfguVfQ==" crossorigin="anonymous"></script>
Upvotes: 1
Reputation: 103
Math.js evaluate function works fine, but when values like 3.2477216E7 comes which contains alphabet "E", then it breaks. can u please let me know, how to handle that.
const obj1 = [{ _id: '5 f467650890a7444d8d9ea5b', keyname: 'fTime',
PTag: '(FaultHrs*360)+(FaultMins*60)+FaultSecs', __v: 0 },
{ _id: '5 f467650890a7444d8d9ea5b', keyname: 'rTime',
PTag: '(RunHrs*360)+(RunMins*60)+RunSecs', __v: 0 }
]
const obj2 = { FaultHrs: 2, FaultMins: 0, FaultSecs: 3.2477216E7, RunHrs: 1, RunMins: 0, RunSecs: 3.2477063E7}
const res = obj1.reduce((res, k) => {
// find out parameters in formula
const matches = k.PTag.match(/[a-zA-Z]+/g);
// substitute them with numbers
const newTag = matches.reduce((tag, m) => tag.replace(m, obj2[m] || 0), k.PTag);
// calculate result, using math.js evaluate function.
res[k.keyname] = math.evaluate(newTag);
return res;
}, {});
console.log(res)
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/7.2.0/math.js" integrity="sha512-O3GZu6Lz0va4Lk7IuF3CjKx5Jfxi35Gcx3oAjH7m7KRP5xvqorrInDpg3OFVJ6dMPn03vHiwgkgPT/hWfguVfQ==" crossorigin="anonymous"></script>
Upvotes: 0
Reputation: 11277
You can try to use New Function()
construct, instead eval()
. Change your code line
res[k.keyname] = eval(newTag);
Into
res[k.keyname] = (new Function(`return ${newTag};`))();
But under the hood it's same eval() actually. Or you could try to roll your own math expression parser, through abstract syntax trees, but there's plenty of them in internet already and besides there is no guarantee that your parser will be superior to integrated and time tested JS engine expression parser.
Upvotes: 1