【问题标题】:RegEx for a^b instead of pow(a,b)正则表达式 a^b 而不是 pow(a,b)
【发布时间】:2011-01-24 01:00:11
【问题描述】:

这里有一个有趣的。任何人都有一个很好的正则表达式来将所有 (first) ^ (second) 转换为 Math.pow((first), (second))?

编辑:

目前为止最好的

s = s.replace(/((?:\d+\.?\d*)|\w+|\((?:(?:[^\(\)]*(?:\([^\(\)]*\)))*)\))\s*\^\s*((?:\d+\.?\d*)|\w+|\((?:(?:[^\(\)]*(?:\([^\(\)]*\)))*)\))/g, 'Math.pow($1, $2)') // replace expression ^ expression with Math.pow($1, $2)

到目前为止的答案还不够笼统。它们不包括 (var1 + var2)^2 之类的东西,更不用说 (var1 * (var2 + var3))^2

解决方案必须使用括号。

您可以使用 strfriend.com 帮助您在创建正则表达式时对其进行可视化。这就是我一直在做的。

【问题讨论】:

  • 你现在最接近的是...?
  • a * b ^ c 应该转换成什么? a ^ b + c? a ^ b ^ c?
  • 这不能用普通的正则表达式来完成。它需要任意递归。如果你想要一个答案,我建议你提高赏金,这是一个相当复杂的问题。
  • 你需要的是一个词法表达式解析器...
  • 已经有一段时间了,但我相信匹配任意括号/引号/字符通常不属于常规语言,因此无法通过正则表达式进行解析。

标签: javascript regex


【解决方案1】:

这不能用正则表达式来完成(至少不是没有很多努力)。您必须考虑不同层次的括号,这是简单的正则表达式无法处理的。我建议寻找一个能够解析数学表达式的库。或者您必须将可能的表达式限制为您可以使用简单的正则表达式处理的内容。

可以在正则表达式中定义命名和平衡捕获组,这些捕获组可以在同一个正则表达式中使用(反向引用)。有了这个,您必须定义所需的数学语法子集以及参数的两个捕获。我建议你不要重新发明轮子并使用 JS 库。

http://snippets.dzone.com/posts/show/2207

【讨论】:

  • 马蒂亚斯就在这里;如果您有一种具有嵌套结构(如括号)的语言,那么常规语言就不会削减它 - 事实上,它存在于“常规语言”的定义中。最好开始编写解析器,或者找到其中的一个。
  • snippets.dzone.com/posts/show/2207 已经死了,你能更新一下吗?
【解决方案2】:

你可以使用String.replace:

> s = "hello 2^3 pow!"
> s.replace(/(\d+)\^(\d+)/, "Math.pow($1, $2)")
"hello Math.pow(2, 3) pow!"

【讨论】:

  • 谢谢!很有用
【解决方案3】:

假设您想要转换源文件或类似的东西,请在您的源文件上运行一个 perl 脚本并使用Math::Expression::Evaluator::Parser。摘自:

use Math::Expression::Evaluator::Parser;

my $exp = '2 + a * 4';
my $ast = Math::Expression::Evaluator::Parser::parse($exp, {});
# $ast is now something like this:
# $ast = ['+',
#          2,
#         ['*',
#          ['$', 'a'],
#          4
#         ]
#        ];

看起来它可以轻松处理求幂。因此,您的 AST 将类似于:

# $ast = ['^',
#         base,
#         exp
#        ];

您可以通过(递归)重新组合来自“base”和“exp”子树的字符串来构建所需的表达式“Math.pow(base, exp)”。

如果您想在 JavaScript 中实现计算器,那么您当然需要 JavaScript-Parser 或者您可以依赖使用 Math::Expression::Evaluator 实现的服务器后端。

【讨论】:

  • 这个,或者一个讨论在 JS 中实现类似功能的答案是正确的答案。
【解决方案4】:

坏消息:正则表达式无法解决问题(正如许多答案所示),您需要为此编写一个解析器。

好消息:通过编写递归下降解析器,您几乎可以用任何语言自己相对轻松地做到这一点。当然,您应该尽可能多地重用现有代码,但建议您自己编写递归下降解析器(并查看您如何编码优先规则),纯粹是为了获得启发性体验。

拿起任何有关编译器构造的书,阅读有关解析的前几章。让我推荐 Niklaus Wirth 的 this freely available book,寻找 4.1 “递归下降的方法”。

【讨论】:

    【解决方案5】:
    var caretReplace = function(_s) {
        if (_s.indexOf("^") > -1) {
            var tab = [];
            var powfunc="Math.pow";
            var joker = "___joker___";
            while (_s.indexOf("(") > -1) {
                _s = _s.replace(/(\([^\(\)]*\))/g, function(m, t) {
                    tab.push(t);
                    return (joker + (tab.length - 1));
                });
            }
    
            tab.push(_s);
            _s = joker + (tab.length - 1);
            while (_s.indexOf(joker) > -1) {
                _s = _s.replace(new RegExp(joker + "(\\d+)", "g"), function(m, d) {
                    return tab[d].replace(/(\w*)\^(\w*)/g, powfunc+"($1,$2)");
                });
            }
        }
        return _s;
    };
    
    1. console.log(caretReplace("(3*(f(x^2)-2)^2+1^5-g(2^3+1)^5)^(9-2^3)"));Math.pow((3*Math.pow((f(Math.pow(x,2))-2),2)+Math.pow(1,5)-Math.pow(g(Math.pow(2,3)+1),5)),(9-Math.pow(2,3)))

    2. 您的数学表达式必须有效,并且开括号和右括号平衡良好。

    3. 您可以将Math.pow 替换为您想要的任何函数名称。

    4. 我通过用非数学文本(___joker___0___joker___1 等)替换所有括号(从最内层到最外层)来做到这一点。最后,我分层解析所有这些字符串,以替换非括号表达式上的插入符号。

    【讨论】:

    • 如果您匹配模式中的可选括号,您可以通过删除多余的括号来增强它。 Here is a demo.
    【解决方案6】:

    看看 Jison,一个 Javascript 解析器生成器。

    特别是查看他们的calculator demo

    【讨论】:

      猜你喜欢
      • 2021-07-15
      • 2021-01-10
      • 2015-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-20
      • 1970-01-01
      • 2014-03-29
      相关资源
      最近更新 更多