【问题标题】:RegEx for matching calculations in strings用于匹配字符串中的计算的正则表达式
【发布时间】:2019-09-20 05:56:29
【问题描述】:

我有一个函数,它可以接受一个字符串,将其解释为计算并返回计算结果,有效计算的示例是:

3(log(e+pi^(22/3)))
44+3*(pi+2)/root(7)

该函数非常繁重,因此我只想在字符串实际上是计算时才运行它。在添加 log 和 root、pi 和 e 以及隐式乘法等函数之前,我使用了以下正则表达式:

/^((-?([0-9]+?\.)?[0-9]+?)\s?([+\-*\/%^]|(\*\*))\s?)+?(-?([0-9]+?\.)?[0-9]+?)$/

这不再起作用了。在这一点上,我什至不确定正则表达式是否对性能有意义。我预计大约 0.1% 的字符串匹配(这是一个有效的计算)。

您对如何创建一个表现良好的常客有任何想法吗? 表达式(函数本身确定天气它是有效的 计算本身,但是需要很长时间,所以没有100%的准确率 需要)或验证计算的函数?

【问题讨论】:

    标签: javascript regex


    【解决方案1】:

    你问的问题本质上是Regular Expression AND String Parsing。 恕我直言,您的字符串计算可以构建为语法树。为它构建一个解析器比创建一个相当复杂的正则表达式更容易。

    【讨论】:

    • 如您的链接所示,用正则表达式匹配任意嵌套的括号是不可能的。
    • @msw 好吧,关键是我认为一个复杂的正则表达式不足以完成这项任务。但仍有一些使用正则表达式的空间。例如,如果某些计算表达式模式在您的数据库中非常频繁,您可以将多个正则表达式组合在一起并使用它们来为您的解析器提供服务。检查这个 [github.com/mozilla/treeherder/pull/181],它用几个已知模式的正则表达式替换了解析器的一些功能。
    【解决方案2】:

    我写了一个验证计算的函数,代码如下:

        const isValidCalc = (calc) => {
        contains = {
            br: false,
            num: false,
            let: false,
            op: false,
        }
        let prev;
        let level = 0;
    
        return ![...calc.replace(/\*\*/g, "^").replace(/ /g, "").replace(/e/g, Math.E).replace(/pi/g, Math.PI)].some(el => {
            if (el === "(") {
                prev = "open";
                level++;
                return false;
            };
            if (el === ")") {
                if (level-- === 0 || prev === "letter") return true;
    
                prev = "close";
                contains.br = true;
                return false;
            }
            if (_.is.Operation(el)) {
                if (prev === "operator" || prev === "letter") return true;
    
                prev = "operator";
                contains.op = true;
                return false;
            }
            if (_.is.Numeric(el) || el === ".") {
                if (prev === "close" || prev === "letter") return true;
    
                prev = "numeric"
                contains.num = true;
                return false;
            }
            if (_.is.Letter(el)) {
                prev = "letter" 
                contains.let = true;
                return false;
            }
    
            return true;
        }) && level === 0 && contains.num && (!contains.let || contains.br) && (contains.let || contains.op);
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-06
      • 2015-07-31
      • 2019-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-16
      相关资源
      最近更新 更多