重写公式字符串以用Math.pow(a,b)替换^ b

时间:2011-02-04 18:20:00

标签: javascript regex parsing

我正在尝试通过让用户输入公式来在HTML5 <canvas>上绘制公式。这通过eval()很有效;但是,^表示Javascript中的按位XOR,而它应该表示公式中的'幂'。

所以基本上我必须重写像x^4Math.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功能?我真的不知道从哪里开始,所以任何提示都会非常感激。

4 个答案:

答案 0 :(得分:7)

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

您可能需要查看Jison,其目的是帮助人们解决此类问题。

正则表达式实际上不是解析标记化字符串的最佳方法。在表达式解析方面,One of Jison's demos 正是正在寻找你正在寻找的东西,让你继续处理函数图形的有趣内容。

答案 1 :(得分:3)

我怀疑这甚至可以用正则表达式来实现。 JS中的正则表达式风格不支持递归模式(即使使用它也会非常麻烦),因此您对((x + 2) * 3)^(x ^ (2 * x))等复杂表达式运气不佳。

如果你想在表达式上进行这样的转换,你可能必须使用正确的标记器和解析器才能从中获取结构。

答案 2 :(得分:1)

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

答案 3 :(得分:1)

    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克(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“等等......)最后,我将分层次地解析所有这些字符串,以替换非括号表达式上的插入符号。