如何在不使用 EVAL 的情况下处理两个数组对象

3

我想处理两个对象。

obj1 数组对象,具有公式。

obj2 具有值。 我希望处理/计算这两个对象,以便在输出中出现obj1中存在的键,并且该值使用公式进行处理。之前用EVAL完成了,但不想再使用它。

请建议其他方法来实现相同的功能。

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)


4
如果输入是可信的——保证是一个数学表达式,没有不安全的代码——那么 eval 可能是最好的选择。它并不是绝对有害的,只是通常情况下不是正确的选项,但这种情况下,在我看来,它是正确的选择。 - CertainPerformance
@CertainPerformance,使用new Function()而不是eval()会更好吧? - bill.gates
@Ifaruki 我不认为在这里有一个更好的选择,你有什么想法吗? - CertainPerformance
1
@CertainPerformance,我读到过new Function()更好、更快,但他们没有详细解释。如果你看一下速度比较https://www.measurethat.net/Benchmarks/Show/2858/0/eval-vs-new-function,实际上有一个差异。 - bill.gates
谢谢你的帮助,我会尝试新的函数。 - Gunjan Anshul
3个回答

1
您可以尝试使用诸如math.js之类的模块,它包含一个评估函数,该函数在底层不使用 eval (我相信旧版本使用了)。
仍然存在安全风险,这些详细信息在math.js文档math.js security中说明,但应该比直接使用eval低。

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>


1
谢谢您的回答,数学计算按预期正常工作。只是想知道是否有办法处理包含 E 的值,例如“6.7452824E7”。 - Gunjan Anshul
我认为math.js应该处理那种格式,我会在我的回答中添加一个例子。 - Terry Lennox
1
我还需要一点帮助,我的一些PTag参数包含下划线和数字。所以当我像这样添加它们时 const matches = k.PTag.match(/[a-zA-Z0-9_]+/g); 我的输出结果是错误的。 - Gunjan Anshul
1
嘿 @GunjanAnshul,我已经更新了答案。问题在于,如果我们使用(/[a-zA-Z0-9_]+/g)作为正则表达式,那么我们将得到数字作为匹配项。因此,我添加了一个要求,即 PTag 必须以字母开头。这样就会得到正确的答案。 - Terry Lennox
1
非常感谢,你节省了很多时间。 - Gunjan Anshul
没问题,很高兴能帮忙! - Terry Lennox

1
你可以尝试使用New Function()构造函数,而不是eval()。更改您的代码行。
 res[k.keyname] = eval(newTag);

Into

res[k.keyname] = (new Function(`return ${newTag};`))();

但实际上在底层它还是使用了eval()函数。或者你可以尝试通过抽象语法树来编写自己的数学表达式解析器,但网络上已经有很多这样的解析器了,而且没有保证你的解析器会比内置的经过时间测试的JS引擎表达式解析器更好。


谢谢,新的函数按预期工作。我想知道如何处理像6.7452824E7这样的值,并想知道我是否使用正确的方法来处理对象数组。 - Gunjan Anshul
1
在表达式中使用特定字符转义您的变量,标记它与用于数字科学表示的 E 符号不同,例如 PTag: '(_RunHrs*360)+(_RunMins*60)+_RunSecs'。然后只匹配可替换字符,如 const matches = k.PTag.match(/_[a-zA-Z]+/g);。通过这种方式,您将跳过不是变量的处理。 - Agnius Vasiliauskas
我需要再请求一次帮助,我的一些参数包含下划线和数字。因此,当我像这样添加它们时,const matches = k.PTag.match(/[a-zA-Z0-9_]+/g); 我的输出结果是错误的。 - Gunjan Anshul
如何在公式中转义变量,这完全取决于个人品味。您可以使用以前从未出现过的符号来转义它,例如 @var@ 或者像 ::var:: 这样的符号组合。不要忘记调整您的正则表达式以正确匹配变量! - Agnius Vasiliauskas

0

Math.js 的 evaluate 函数运行良好,但当出现包含字母“E”的值,如3.2477216E7时,它会出错。请问如何处理这种情况。

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>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接