Разделение регулярных выражений дает приоритет одному символу над другим - PullRequest
0 голосов
/ 04 января 2019

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

Примеры:

"123x849-302 + 450" -> ["123", "849", "302", "450"]

"124x (145 + 301) x402 + (- 402)" -> ["124", "145 + 301", "402", "-402"]

"124x ((234 + 403) / 354)) + (- 21)" -> ["124", "(234 + 403) / 354", "-21"]

По сути, если есть скобки, мне нужно получить токен внутри скобок, в противном случае просто разделить в соответствии с оператором.

Мне очень плохо с регулярным выражением, и я знаю только самые основы. Я понятия не имею, как включить скобки в регулярное выражение, и сейчас все, что у меня есть, это:

String delim = "[x+/-]";
String[] tokens = equation.toString().split(delim);

ToString существует, потому что уравнение является StringBuilder.

Ответы [ 2 ]

0 голосов
/ 04 января 2019

Понятие «регулярный» синтаксис является академическим понятием. «Регулярные выражения» имеют правильные имена: они могут анализировать любой «обычный» синтаксис, но их нельзя использовать для анализа нерегулярного синтаксиса.

Давайте определим «базовую математику» как сочетание чисел, 4 операторов: +-*/ и скобок.

«основные математические» - это не регулярно .

Поэтому его нельзя анализировать с помощью регулярных выражений.

То, что вы хотите, это парсер, который может превратить это:

a+x*y+(b-c)*e

в эту структуру данных:

          PLUS
      /           \
    PLUS          TIMES
  /     \         /     \
a      TIMES    MINUS   e
      /   \    /  \
      x   y    b   c

Могут использоваться различные технологии синтаксического анализа, такие как рекурсивный спуск или пакетирование (например, с использованием библиотеки анализатора граппа / пропаренный), а также различные технологии синтаксического анализа на основе LALR и LL (k), такие как ANTLR. Обычно это очень сложные технологии; возможно, для чего-то такого тривиального вы можете написать для этого собственный анализ на основе рекурсивного спуска.

Но, возвращаясь к исходному вопросу, если вы хотите разделить a+x*y+(b-(g+h))*e на: ['a', 'x', 'y', '(b- (g + h))', 'e '], что является лишь частью того, что вам нужно, поскольку теперь вам все еще нужно разобраться, что делать с узлом' (b- (g + h)) ', регулярное выражение просто не может этого сделать: вы хотите, чтобы ваше регулярное выражение см. открытие ( прямо перед b в качестве начала блока скобок, а затем ... вашему регулярному выражению нужно СЧИТАТЬ количество открывающих паренов, а затем найти столько закрывающих паренсов и проигнорировать их, а затем закрывающий член после тех, кто побеждает. Итак, это регулярное выражение:

String elementPattern = "(\\([^\\)]+\\)|[^-+*/\\(\\)]+)";
Pattern p = Pattern.compile("^\\s*" + elementPattern + "(\\s*[-+*/]\\s*" + elementPattern + ")*$");

, который на первый взгляд, кажется, выполняет работу, на самом деле не может выполнить эту работу: он перестал бы рассматривать часть (b-(g+h)) в FIRST из 2 закрывающих паренов и, таким образом, не соответствовал , Необходимо остановиться на втором, но регулярные выражения не имеют никакого способа сделать это, потому что это не «регулярный».

0 голосов
/ 04 января 2019

Я не думаю, что регулярное выражение будет правильным инструментом. Я не знаю, какова конечная цель, но если вам просто нужно разделить выражение, как в вашем вопросе, вы можете попробовать что-то вроде этого:

private static List<String> splitExpr(String expr) {
    List<String> result = new ArrayList<>();
    StringBuilder buf = new StringBuilder();
    int level = 0;
    int st = 0;
    for (char c: expr.toCharArray()) {
        if (level > 0) {
            // we're in a subexpression
            if (c == '(') {
                ++level;
            } else if (c == ')') {
                --level;
            }
            if (level == 0) {
                result.add(buf.toString());
                st = 2;
            } else {
                buf.append(c);
            }
        } else {
            switch (st) {
                case 0:
                    // initial state
                    if (Character.isDigit(c)) {
                        // first digit of a number
                        buf.setLength(0);
                        buf.append(c);
                        st = 1;
                    } else if (c == '(') {
                        // beginning of a subexpression
                        buf.setLength(0);
                        ++level;
                    } else {
                        // error: ignore unexpected character
                    }
                    break;
                case 1:
                    // inside a number
                    if (Character.isDigit(c)) {
                        // next digit
                        buf.append(c);
                    } else if (c == '+' || c == '-' || c == 'x' || c == 'X'
                            || c == '/') {
                        // operator; the number is finished, add it to the list
                        result.add(buf.toString());
                        st = 0;
                    } else {
                        // error: ignore unexpected character
                    }
                    break;
                case 2:
                    // after a subexpression
                    if (c == '+' || c == '-' || c == 'x' || c == 'X'
                            || c == '/') {
                        st = 0;
                    } else {
                        // error: ignore unexpected character
                    }
                    break;
            }
        }
    }
    if (level == 0 && st == 1) {
        // in a number at the end of string: add the number to the list
        result.add(buf.toString());
    }
    return result;
}

для ваших примеров:

123x849-302+450: [123, 849, 302, 450]
124x(145+301)x402+(-402): [124, 145+301, 402, -402]
124x((234+403)/354))+(-21): [124, (234+403)/354, -21]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...