Совпадения нулевой длины в Java Regex - PullRequest
8 голосов
/ 28 марта 2012

Мой код:

Pattern pattern = Pattern.compile("a?");
Matcher matcher = pattern.matcher("ababa");
while(matcher.find()){
   System.out.println(matcher.start()+"["+matcher.group()+"]"+matcher.end());
}

Вывод:

0[a]1
1[]1
2[a]3
3[]3
4[a]5
5[]5

Что я знаю:

  • "a?"обозначает ноль или одно вхождение символа 'a'.

Java API говорит:

  • matcher.start () возвращает начальный индекс предыдущего совпадения.
  • matcher.end () возвращает смещение после сопоставления последнего символа.
  • matcher.group () возвращает входную подпоследовательность, сопоставленную с предыдущим соответствием.Для сопоставителя m с входной последовательностью s выражения m.group () и s.substring (m.start (), m.end ()) эквивалентны.А для некоторых шаблонов, например *, соответствует пустая строка.Этот метод возвращает пустую строку, когда шаблон успешно соответствует пустой строке во входных данных.

Что я хочу знать:

  1. В каких ситуациях работает механизм регулярных выраженийвстречает нулевое вхождение заданного символа (символов) - Здесь для символа 'a'.
  2. В этих ситуациях, какие значения фактически возвращаются методами start (), end () и group () в matcher,Я упомянул то, что сказал API Java.Но мне немного неясно, когда дело доходит до практической ситуации, описанной выше.

Ответы [ 2 ]

11 голосов
/ 28 марта 2012

? - это жадный квантификатор, поэтому он сначала попытается сопоставить 1-вхождение, прежде чем пытаться 0-вхождение. В твоей строке

  1. он начинается с первого символа 'a' и пытается найти совпадение с 1-кратным совпадением. Символ 'a' совпадает, и поэтому он возвращает первый результат, который вы видите
  2. затем он движется вперед и находит 'b'. Символ 'b' не соответствует вашему регулярному выражению 1-вездес, поэтому двигатель возвращается назад и пытается соответствовать 0-вездесущему. Результатом является совпадение пустой строки -> вы получите второй результат.
  3. затем он опережает b, так как там больше нет совпадений и начинается снова с вашим вторым символом 'a'.
  4. и т.д.

Это немного сложнее, но это главная идея. Когда 1-вхождение не может совпадать, оно попытается использовать 0-вхождение.

Что касается значений начала, конца и группы, они будут в том месте, где начинается, заканчивается совпадение, а группа - это то, что было сопоставлено, поэтому в первом совпадении с 0 вхождением вашей строки вы получаете 1, 1 и строка emtpy. Я не уверен, что это действительно отвечает на ваш вопрос.

3 голосов
/ 28 марта 2012

Повтор нескольких примеров прояснит вам функционирование matcher.find():

Движок Regex берет один символ из строки (т.е. ababa) и пытается найти, найден ли искомый шаблон в строке или нет. Если шаблон существует, то (как упомянуто API):

matcher.start () возвращает начальный индекс, matcher.end () возвращает смещение после последнего найденного символа.

Если совпадений не существует. затем start () и end () возвращают один и тот же индекс, который должен соответствовать согласованной длине, равной нулю.

Посмотрите на следующие примеры:

        // Searching for string either "a" or ""
        Pattern pattern = Pattern.compile("a?");
        Matcher matcher = pattern.matcher("abaabbbb");
        while(matcher.find()){
           System.out.println(matcher.start()+"["+matcher.group()+"]"+matcher.end());
        }

Выход:

    0[a]1
    1[]1
    2[a]3
    3[a]4
    4[]4
    5[]5
    6[]6
    7[]7
    8[]8


      // Searching for string either "aa" or "a"
       Pattern pattern = Pattern.compile("aa?");
    Matcher matcher = pattern.matcher("abaabbbb");
    while(matcher.find()){
       System.out.println(matcher.start()+"["+matcher.group()+"]"+matcher.end());
    }

Выход:

0[a]1
2[aa]4
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...