在 Javascript 中我自己的类似函数的评估

Eval like function by my own in Javascript

我正在尝试在 Javascript 中创建类似 eval() 的函数(从字符串计算表达式)。 我在连续的“-”操作中遇到错误。 除了“-”之外,一切正常。 谁能帮我让“-”工作 用于实时预览代码笔 link- https://codepen.io/raj1998211/pen/yvVXLd

function mat(str){
  // var sum = 0;
  ns = str;
  while(ns.indexOf('/') > 0){
    var regex = /(\d+|(\d+\.\d+))(\/)((\d+\.\d+)|\d+)/g;
     var ns = ns.replace(regex, function(a){
      arr = a.split("/");    
      ans = Number(arr[0]) / Number(arr[1]);
      return ans;
    });
    // console.log(ns);
  }
  while(ns.indexOf('*') > 0){
    var regex = /(\d+|(\d+\.\d+))(\*)((\d+\.\d+)|\d+)/g;
    var ns = ns.replace(regex, function(a){
      arr = a.split("*");    
      ans = Number(arr[0]) * Number(arr[1]);
      return ans;
    });
    // str = ns;
    // console.log(ns);
  }

  while(ns.indexOf('-') > 0){
    var regex = /(\-\d+|\d+|(\d+\.\d+))(\-)((\d+\.\d+)|\d+)/g;
    var ns = ns.replace(regex, function(a){
      arr = a.split("-");    
      ans = Number(arr[0]) - Number(arr[1]);
      return Math.abs(ans);
      // return ans;
    });
    // console.log(ns);
  }
//   if(ns.indexOf('-') === 0){

//   }

  if(ns.indexOf('+') > 0){
    arr = ns.split("+");
    sum = 0;
    for(i = 0; i < arr.length; i++){
      sum += Number(arr[i]);
    }
    ns = sum;
  }
  // return "sum";
  return ns;
}

console.log(mat("4-5-1")); //infinite loop if '-' comes on first char of str

您应该考虑这是否按预期工作,因为任何负数都会破坏您的代码。 (例如:垫子(“1+-1”))。考虑正则表达式是否具有解析表达式所需的表达能力,因为它们非常有限。 (例如,您不能单独使用正则表达式检查平衡括号)

您可能想研究解析,网上有很多教程对此进行了描述。

你可能还想看看正则语言的局限性(这是正则表达式可以表达的/"parse")

下一步可能是研究所谓的 "context free grammars",它具有更强的表达能力。

对于完整的解析,一些有用的关键字是 "Tokenizing" 和 "Abstract syntax trees"。希望其中的一些可以帮助您研究您需要的东西。

问题是 4-5 产生 -1,所以在第一次替换后你得到

-1-1,导致无限循环,或者,使用您的 abs() hack

1-1,导致错误的结果。

一个选择是删除 abs() hack 并使用 ns.indexOf('-', 1),但这可能会导致负数出现问题——而且您的数字正则表达式似乎无法处理也有负数......所以你也需要解决这个问题。

解决此问题的一个选项可能是:

  • 添加一个预处理步骤,用其他字符替换所有被数字包围的“-”,例如'%'
  • 所有剩余的 '-' 都是一元的。相应地扩展您的正则表达式以包含一元减号
  • 更改二进制负处理代码以改为使用“%”。

或者,您可以使用这样的递归方法代替术语重写方法:

function mat(str) {
  var operators = "/*-+"; 
  for (var i = 0; i < 4; i++) {
    var op = operators.charAt(i);
    var pos = str.indexOf(op);
    if (pos > 0 && operators.indexOf(str.charAt(pos - 1)) == -1) {
      var left = mat(str.substr(0, pos));
      var right = mat(str.substr(pos + 1));
      switch (op) {
        case "/": return left / right;
        case "*": return left * right;
        case "-": return left - right;
        case "+": return left + right; 
      }
    }
  }
  return Number(str);
}