RegEx для сопоставления расчетов в строках - PullRequest
0 голосов
/ 01 мая 2019

У меня есть функция, которая может взять строку, интерпретировать ее как вычисление и вернуть результат вычисления, примеры правильных вычислений:

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% строк будут совпадать (что является правильным расчетом).

Есть ли у вас какие-либо идеи о том, как создать хорошо работающий регулярный выражение (сама функция определяет погоду Сам расчет, но это занимает много времени, поэтому нет 100% точности необходимо) или функция, которая проверяет расчет?

Ответы [ 2 ]

1 голос
/ 01 мая 2019

Вопрос, который вы задаете, по сути Регулярное выражение и анализ строки . ИМХО, ваш расчет строки может быть построен как синтаксическое дерево. Было бы проще создать для него парсер, чем создать довольно сложное регулярное выражение.

0 голосов
/ 02 мая 2019

Я написал функцию, которая проверяет вычисления, вот код:

    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);
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...