Математическая формула - Подстановка переменных с помощью регулярных выражений - PullRequest
1 голос
/ 12 января 2020

Я работаю над функцией Javascript, которая оценивает введенную пользователем строку как математическую формулу.

Например, пользователь может ввести 1 + 1, и функция оценит ее как 2. Я использую библиотеку, чтобы сделать это, поэтому математика и синтаксис уже обработаны для этого. Однако у меня есть переменные, на которые пользователь может ссылаться. Пользователь может создать числовую переменную, дать ей имя (по своему выбору) и ссылаться на нее в уравнении. Предположим, что пользователь пишет 1 + counter, библиотека math eval, очевидно, не знает, что такое counter, поэтому я использую регулярные выражения для предварительной обработки формулы. Функция предварительной обработки увидит counter, найдет его значение и заменит его литералом. Поэтому, если пользователь установил counter на 3 в другом месте, моя функция примет 1 + counter, заменит счетчик на 3, чтобы получить 1 + 3, а затем отправит формулу в библиотеку математических вычислений.

У меня проблема в написании функции, которая обрабатывает это с помощью регулярных выражений. Я начинаю с регулярного выражения ([^A-Za-z0-9])counter($|[^A-Za-z0-9]), которое соответствует counter, только если по обе стороны от него нет другого алфавитного символа c. Например, пользователь может в какой-то момент набрать counter2, и я хочу убедиться, что поиск counter2 найден, но counter не будет совпадать. В сущности, чтобы повысить производительность, я фактически использую переменные oop, генерирую для них регулярные выражения и сопоставляю их таким образом. Некоторые из них могут не совпадать вообще, но они выполняются в O (n), вместо того, чтобы искать список переменных для каждой ссылки в массиве. Другими словами, я не строю синтаксическое дерево или что-то еще, поэтому, если бы у меня были переменные counter и counter2, я бы сгенерировал регулярное выражение для каждой и попытался бы сопоставить их, следовательно, если бы формула была counter2, функция все еще пытается найти соответствие для counter и counter2, но должно совпадать только counter2.

Я использую следующий код:

var re = new RegExp(`(^|[^A-Za-z0-9])${variableName}($|[^A-Za-z0-9])`, "g");

let match = re.exec(formula);

while (match !== null) {
  // If "+counter+" is matched, I have to make sure that the +'s remain, hence replacing on the match
  var sub = match[0].replace(`${variableName}`, `{${variableValue}}`);

  formula = formula.replace(match[0], sub)

  re.lastIndex = 0; // just reset to the start for now
  match = re.exec(formula);
}

// Pass to math library next

Это работает в большинстве случаев, но у меня возникает следующая проблема:
Для формулы counter+counter совпадают только первые counter+, когда оба должны совпадать.

Итак, мне нужно в основном регулярное выражение / функция что делает следующее:

  • Примите имя переменной
  • Замените все вхождения, если в них нет буквенно-буквенного символа c спереди или сзади. Поэтому, если я сопоставлю counter с формулой, +counter+ будет соответствовать (+ не являются alphanumeri c), + counter будет соответствовать (пробел не alphanumeri c), но counter2 не будет не совпадают, потому что это совершенно другое имя переменной, а 2 - это alphanumeri c.

Есть идеи? Я пытаюсь сделать это правильно, я думаю, что может быть много неизвестных побочных эффектов, если я не сделаю это правильно.
Спасибо за помощь!

1 Ответ

1 голос
/ 12 января 2020

Вы можете использовать в конце заглядывание, (?=$|[^A-Za-z0-9]) вместо ($|[^A-Za-z0-9]) группы захвата, и уменьшить код в большей степени, если вы просто используете replace:

var re = new RegExp(`(^|[^A-Za-z0-9])${variableName}(?=\$|[^A-Za-z0-9])`, "g");
formula = formula.replace(re, "$1"+variableValue)

Примечание $1 в замещающей части - это обратная ссылка на значение, сохраненное в Группе 1, то есть начало строки или любого символа, кроме ASCII alphanumeri c (захвачено с помощью (^|[^A-Za-z0-9])).

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