Какое состояние сохраняет Java matcher.find() после неудачного сопоставления с квантификаторами?

В дальнейшем я ожидаю, что второй find() будет успешным, но это не так. Почему?

Matcher matcher = 
    Pattern.compile("\\s*asdf").matcher("apple banana cookie");

// returns false as expected
matcher.find();

// resets groups (that weren't being explicitly being used anyway), but not state.
matcher.usePattern(Pattern.compile("\\s*banana")); 

// returns false, expected true.
System.out.println(matcher.find());

Если квантификатор удаляется из первого регулярного выражения (становится просто asdf), второе совпадение завершается успешно. Глядя на объект Matcher, мы обнаруживаем, что какая-то групповая информация сохраняется после первого неудачного find(), хотя я этого не ожидал. Find() — это предполагается начинать либо с начала (если нет предыдущего совпадения), либо с индекса последнего успешного совпадения. UsePattern() — это предполагалось сохранять позицию Matcher во входных данных и отбрасывать информацию о группе (которую, опять же, я не использовал явно).

Я что-то упускаю, но не знаю что. Я подозреваю, что мне нужно реализовать это с помощью lookAt() и обновить регион (например, этот пример), но я не знаю, почему этот подход не работает.


person Rich Fletcher    schedule 14.06.2011    source источник


Ответы (2)


Похоже, документация немного вводит в заблуждение (или на самом деле в ней просто не указано), какое поведение происходит, когда вы вызываете find() после сбоя.

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

Глядя на файл исходный код подтверждает, что Matcher имеет индекс (поле last), с которого он начинает поиск при выполнении следующего 'find()', и когда find() терпит неудачу, этот индекс доведен до конца и не сбрасывается.

reset() сбрасывает этот индекс, usePattern() нет.

person trutheality    schedule 14.06.2011
comment
В моей реализации я использую сопоставитель для сохранения состояния в рекурсивном вызове, поэтому для решения исходной проблемы я сохраняю старый регион и регион вызова (oldStart, oldEnd), который сбрасывает сопоставитель перед установкой границ. - person Rich Fletcher; 14.06.2011
comment
Регион отличается от внутреннего «последнего» поля. Вы можете проверить это: вызов find не меняет регион. - person trutheality; 14.06.2011

Ваше первое регулярное выражение использует всю строку (\\\\s*). Когда запускается второе регулярное выражение, ничего не остается для сопоставления.

Если вы вызываете matcher.reset(), он работает так, как ожидалось.

person adotout    schedule 14.06.2011
comment
Хорошо, внимательно перечитайте Matcher JavaDoc с учетом этого показывает, что сопоставитель находит совпадения в подмножестве своих входных данных, называемом регионом. По умолчанию регион содержит все входные данные сопоставителя. Насколько я могу судить, в документации определен только метод region() для изменения региона (хотя кажется довольно очевидным, что регион модифицируется в другое время, отсюда и путаница). Итак, find() действительно изменяет регион? - person Rich Fletcher; 14.06.2011