Перепишите строку формулы, чтобы заменить a ^ b на Math.pow (a, b) - PullRequest
3 голосов
/ 04 февраля 2011

Я сейчас пытаюсь построить формулы в HTML5 <canvas>, позволяя пользователю вставить формулу. Это прекрасно работает через eval(); однако ^ означает побитовый XOR в 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 помещались только правильные части? Я действительно не вижу, с чего начать, поэтому любые советы будут с благодарностью.

Ответы [ 4 ]

7 голосов
/ 04 февраля 2011

Это сложный вопрос. Здесь вы говорите о парсере выражений.

Возможно, вы захотите взглянуть на Jison , который призван помочь людям решить этот тип проблемы.

Регулярные выражения на самом деле не лучший способ разбора токенизированных строк. Одна из демонстраций Jison - это точно , то, что вы ищете, с точки зрения синтаксического анализа выражений, позволяя вам поработать над забавными графическими функциями.

3 голосов
/ 04 февраля 2011

Я сомневаюсь, что это даже выполнимо с регулярным выражением. Вариант регулярных выражений в JS не поддерживает рекурсивные шаблоны (и было бы крайне сложно сделать это даже с этим), поэтому вам не повезло с такими сложными выражениями, как ((x + 2) * 3)^(x ^ (2 * x)).

Если вы хотите иметь возможность выполнять подобные преобразования в выражении, вам, вероятно, придется использовать надлежащий токенизатор и анализатор, чтобы вытащить из него структуру.

1 голос
/ 07 августа 2013
    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. Ваше математическое выражение должно быть с хорошо сбалансированными открытыми и закрытыми скобками (допустимое выражение).

  2. Вы можете заменить «Math.pow» любым именем функции.

  3. Я сделал это, заменив все скобки, от самых внутренних до самых внешних, нематематическими текстами (" _joker _0", " _joker _1 "и т. Д.) В конце я анализирую все строки тезисов иерархически, чтобы заменить каретки на выражения без скобок.

1 голос
/ 04 февраля 2011

Как правило, этот тип проблемы решается с использованием лексеров и парсеров , а не регулярных выражений. Из-за порядка операций математических выражений вам необходимо понимать целое выражение (и все его части), а не только степень его части. Я не уверен, какие парсеры обычно используются для Javascript, но кажется, что ANTLR имеет цель для генерации парсеров Javascript: http://www.antlr.org/wiki/display/ANTLR3/ANTLR3JavaScriptTarget

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...