Я работаю над функцией 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.
Есть идеи? Я пытаюсь сделать это правильно, я думаю, что может быть много неизвестных побочных эффектов, если я не сделаю это правильно.
Спасибо за помощь!