Подтвердить что ты не робот

Регулярное выражение с переменным числом групп?

Можно ли создать регулярное выражение с переменным числом групп?

После запуска этого примера...

Pattern p = Pattern.compile("ab([cd])*ef");
Matcher m = p.matcher("abcddcef");
m.matches();

... Я хотел бы иметь что-то вроде

  • m.group(1)= "c"
  • m.group(2)= "d"
  • m.group(3)= "d"
  • m.group(4)= "c".

(Предыстория: я разбираю некоторые строки данных, и одно из "полей" повторяется. Я бы хотел избежать цикла matcher.find для этих полей.)


Как указано @Tim Pietzcker в комментариях, perl6 и . NET имеют эту функцию.

4b9b3361

Ответ 1

Согласно документации, регулярные выражения Java не могут этого сделать:

Захваченный вход, связанный с группа всегда является подпоследовательностью, которая группа в последний раз. Если группа оценивается второй раз из-за ранее зафиксированное значение, если оно есть, будут сохранены, если вторая оценка не выполняется. Соответствие строки "aba" против выражения (a (b)?) +, например, оставляет группу 2, установленную в "Б". Весь захваченный вход отбрасывается в начале каждого матча.

(выделено курсивом)

Ответ 2

Pattern p = Pattern.compile("ab(?:(c)|(d))*ef");
Matcher m = p.matcher("abcdef");
m.matches();

должен делать то, что вы хотите.

EDIT:

@aioobe, я понимаю сейчас. Вы хотите сделать что-то вроде грамматики

A    ::== <Foo> <Bars> <Baz>
Foo  ::== "foo"
Baz  ::== "baz"
Bars ::== <Bar> <Bars>
        | ε
Bar  ::== "A"
        | "B"

и вытащите все индивидуальные совпадения Bar.

Нет, нет способа сделать это с помощью java.util.regex. Вы можете повторять и использовать регулярное выражение в матче Bars или использовать генератор синтаксического анализатора, например ANTLR, и прикрепить побочный эффект к Bar.

Ответ 4

Я не использовал java regex, но для многих языков ответ: No.

Захватывающие группы, похоже, создаются, когда регулярное выражение анализируется и заполняется, когда оно соответствует строке. Выражение (a)|(b)(c) имеет три группы захвата, только если один или два из них могут быть заполнены. (a)* имеет только одну группу, парсер оставляет последнее совпадение в группе после сопоставления.

Ответ 5

Я бы подумал, что откат тормозит это поведение и говорит о влиянии /([\S\s])/ на накопительное состояние группировки на нечто вроде Библии. Даже если это можно сделать, вывод непознаваем, поскольку группы потеряют позиционное значение. Лучше сделать отдельное регулярное выражение на подобном виде в глобальном смысле и внести его в массив.

Ответ 6

У меня только была очень похожая проблема, и мне удалось сделать "переменное число групп", но комбинация цикла while и сброса совпадения.

    int i=0;
    String m1=null, m2=null;

    while(matcher.find(i) && (m1=matcher.group(1))!=null && (m2=matcher.group(2))!=null)
    {
        // do work on two found groups
        i=matcher.end();
    }

Но это для моей проблемы (с двумя повторяющимися

    Pattern pattern = Pattern.compile("(?<=^ab[cd]{0,100})[cd](?=[cd]{0,100}ef$)");
    Matcher matcher = pattern.matcher("abcddcef")
    int i=0;
    String res=null;

    while(matcher.find(i) && (res=matcher.group())!=null)
    {
        System.out.println(res);
        i=matcher.end();
    }

Вы теряете возможность указывать произвольную длину повторения с помощью * или +, потому что внешний вид и внешний вид должны быть предсказуемой длины.