У меня есть функция, которая может принимать строку, интерпретировать ее как вычисление и возвращать результат вычисления, примеры допустимых вычислений:
3(log(e+pi^(22/3)))
44+3*(pi+2)/root(7)
функция довольно тяжелая, поэтому я хотел бы запускать ее только в том случае, если String действительно является вычислением. Прежде чем я добавил такие функции, как log и root, pi и e и неявное умножение, я использовал следующее регулярное выражение:
/^((-?([0-9]+?\.)?[0-9]+?)\s?([+\-*/%^]|(\*\*))\s?)+?(-?([0-9]+?\.)?[0-9]+?)$/
который больше не работает. На данный момент я даже не уверен, будет ли регулярное выражение иметь смысл с точки зрения производительности. Я ожидаю, что около 0,1% строк совпадут (это правильный расчет).
Do you have any ideas on how to create a well performing regular expression (the function itself determines weather its a valid calculation itself, but it takes a long time, so no 100% accuracy needed) or a function which validates the calculation?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вопрос, который вы задаете, по сути Регулярные выражения и анализ строк. ИМХО, ваш строковый расчет можно построить как синтаксическое дерево. Было бы проще построить парсер для него, чем создавать довольно сложное регулярное выражение.
@msw Ну, дело в том, что я не думаю, что одного сложного регулярного выражения достаточно для выполнения этой задачи. Но еще есть место для использования регулярных выражений. Например, если некоторые шаблоны выражений вычислений очень часто встречаются в вашей базе данных, вы объединяете несколько регулярных выражений вместе и используете их для обслуживания части вашего синтаксического анализатора. Проверьте этот [github.com/mozilla/treeherder/pull/181], он заменил некоторые функции парсера несколькими регулярными выражениями для известных шаблонов.
Я написал функцию, которая проверяет вычисление, вот код:
const isValidCalc = (calc) => {
contains = {
br: false,
num: false,
let: false,
op: false,
}
let prev;
let level = 0;
return ![...calc.replace(/\*\*/g, "^").replace(/ /g, "").replace(/e/g, Math.E).replace(/pi/g, Math.PI)].some(el => {
if (el === "(") {
prev = "open";
level++;
return false;
};
if (el === ")") {
if (level-- === 0 || prev === "letter") return true;
prev = "close";
contains.br = true;
return false;
}
if (_.is.Operation(el)) {
if (prev === "operator" || prev === "letter") return true;
prev = "operator";
contains.op = true;
return false;
}
if (_.is.Numeric(el) || el === ".") {
if (prev === "close" || prev === "letter") return true;
prev = "numeric"
contains.num = true;
return false;
}
if (_.is.Letter(el)) {
prev = "letter"
contains.let = true;
return false;
}
return true;
}) && level === 0 && contains.num && (!contains.let || contains.br) && (contains.let || contains.op);
};
Как показывает ваша ссылка, невозможно сопоставить произвольно вложенные скобки с регулярными выражениями.