【问题标题】:Rewrite formula string to replace a^b with Math.pow(a, b)重写公式字符串以将 a^b 替换为 Math.pow(a, b)
【发布时间】:2011-06-21 13:13:27
【问题描述】:

我目前正试图通过让用户输入公式来在 HTML5 <canvas> 上绘制公式。这通过eval() 很有效;但是,^ 在 Javascript 中表示按位异或,而在公式中应该表示“幂”。

所以基本上我必须将x^4 之类的东西重写为Math.pow(x, 4)。我想出了使用正则表达式。然而,这仅在一定程度上起作用:

"x^4".replace(/(.*)\^(.*)/g, "Math.pow($1, $2)")

它确实将x^4 重写为Math.pow(x, 4),但对于更高级的公式,这会出错。例如,2 + x^4 被重写为Math.pow(2 + x, 4),当然它应该是2 + Math.pow(x, 4)。此外,如果指数周围有括号,例如2^(x+1) + 3,当然应该改写成Math.pow(2, x+1) + 3而不是Math.pow(2, x+1 + 3)

我将如何重写它以便只将正确的部分放入 pow 函数中?我真的不知道从哪里开始,所以任何提示将不胜感激。

【问题讨论】:

  • 您的正则表达式也需要更彻底地适应系数。您可能应该让它检查变量前后的空格,并通过注入* 将系数与变量分开。您还必须实现 () 指示的相同语法规则
  • @Joel 感谢您的提示。 @Ben 抱歉没看到那个,谢谢。
  • — 不用担心!我只是想确保您不会错过答案中包含的信息。 :-)

标签: javascript regex parsing


【解决方案1】:

这是一个棘手的问题。你这里说的是表达式解析器。

您可能想看看Jison,它旨在帮助人们解决此类问题。

正则表达式并不是解析标记化字符串的最佳方式。 One of Jison's demos 正是您正在寻找的,就表达式解析而言,让您可以从事函数图形的有趣工作。

【讨论】:

  • 实际上,出于某种原因,这似乎也比eval很多
  • 感谢该计算器的链接。但是语法有缺陷,它说 -2^2 等于 4,而实际上它应该是 -4 作为 wolfram alpha 和谷歌状态。顺便说一句,MS Excel 也有同样的错误,它给出了 4。
  • @keithphw,实际上,该表达式不是唯一定义的。它可以在数学上解释为 (-2)^2 或 -(2^2)。在编程语言中,它由运算符优先级表很好地定义。在数学中,这更像是一个约定问题,在这种情况下,这里没有明确的约定
  • 感谢您的回复丹。我认为有一个约定,即操作顺序。幂在减法和乘法之前(负一)。 MS excel 是我所知道的所有主要程序中唯一的异常值。顺便说一句,您会对 Jison 演示进行哪些编辑以使其给出 -2^2 = -4?
  • 看起来否定的优先级目前是最高的。我会将那个移到乘法旁边,并将取幂作为最高优先级
【解决方案2】:

我怀疑这对正则表达式是否可行。 JS 中的正则表达式风格不支持递归模式(即使这样做也会非常麻烦),因此您对复杂的表达式(例如 ((x + 2) * 3)^(x ^ (2 * x)))不走运。

如果您希望能够对表达式进行这样的转换,您可能必须使用适当的标记器和解析器才能从中获取结构。

【讨论】:

    【解决方案3】:

    通常使用lexersparsers 来解决此类问题,而不是正则表达式。由于数学表达式的运算顺序,您需要了解整个表达式(及其所有部分),而不仅仅是幂部分。我不确定哪些解析器通常用于 Javascript,但似乎 ANTLR 有一个生成 Javascript 解析器的目标:http://www.antlr.org/wiki/display/ANTLR3/ANTLR3JavaScriptTarget

    【讨论】:

      【解决方案4】:
          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”等...)。最后,我分层解析所有这些字符串,以替换非括号表达式上的插入符号。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多