Продолжаем изучение регулярных выражений.
В этой статье мы рассмотрим предопределенные классы символов, а также квантификацию (поиск последовательностей).
![Основы регулярных выражений в Java. Часть 3 - 1]()
В этой таблице конструкции в левой колонке — сокращенное представление выражений из правой колонки. Например, ![Основы регулярных выражений в Java. Часть 3 - 3]()
В первых трех примерах регулярное выражение — просто «
Квантификаторы позволяют задавать количество вхождений символа в строку. Рассмотрим подробнее тонкости работы жадных, ленивых и очень жадных квантификаторов. На первый взгляд может показаться, что квантификаторы X?, X?? и X?+ работают одинаково: «X есть один раз или нет совсем». Есть небольшие отличия в реализации этих квантификаторов, которые мы рассмотрим ниже.
В примере выше, поиск был удачным в первых двух случаях, потому что выражения a? и a* допускают отсутствие символа a в строке. Также обратите внимание, что начальный и последний индексы совпадения одинаковы (0). Так как входная строка не имеет длины, программа находит ничего :) на первой же позиции. Этот случай называется совпадением нулевой длины. Такие совпадения встречаются в нескольких случаях: при пустой входной строке, в начале входной строки, после последнего символа строки или между символами строки. Совпадения нулевой длины легко обнаружить: они начинаются и заканчиваются на одной и той же позиции.
Рассмотрим еще несколько примеров совпадений нулевой длины.
Let’s explore zero-length matches with a few more examples. Изменим входную строку на символ «a» и наблюдаем интересный эффект:
Все три квантификатора нашли символ «a», но первые два, которые допускают отсутствие символа, нашли совпадение нулевой длины на позиции 1 — после последнего символа строки. Так происходит, потому что программа воспринимает символ «a» как строку и «бежит» по ней пока совпадения не закончатся. В зависимости от используемого квантификатора, программа будет или не будет находить «ничего» в конце строки.
Теперь изменим входную строку на последовательность из пяти букв «a»:
Регулярное выражение a? находит совпадение для каждой буквы в строке отдельно. Выражение a* находит два совпадения: последовательность символов «a»‘ и совпадение нулевой длины на 5 позиции. И, наконец, регулярное выражение a+ находит только последовательность символов «a», не находя при этом «ничего» :)
Что же будет происходить, если на вход подать строку, содержащую разные символы? Например, «ababaaaab»:
Символ «b» находится на 1, 3 и 8 позициях и программа находит совпадения нулевой длины на этих позициях. Регулярное выражение a? не обращает внимания на «b», а просто ищет присутствие (или отсутствие) символа «a». Если квантификатор допускает отсутствие «a» все символы в строке отличные от «a» будут показаны как совпадение нулевой длины.
Для нахождения последовательностей заданной длины, просто укажите длину в фигурных скобках:
Регулярное выражение a{3} ищет последовательность из трех символов «a». В первой строке ничего не найдено, потому что в строке недостаточно символов a. Вторая содержит 3 символа, которые и находит программа. Третий тест также находит совпадение в начале строки. Все что находится за 3 символом не удовлетворяет регулярному выражению, в коде ниже — удовлетворяет и найдутся несколько совпадений:
Для указания минимальной длины последовательности — используйте:
В этом примере первое совпадение закончилось на шестом символе. Второе совпадение содержит символы после шестого, т.к. они удовлетворяют требованию минимальной длины. Если бы строка была на один символ короче, второго совпадения не было бы.
В первом примере программа находит совпадение, т.к. квантификатор распространяется на группу символов. Если убрать скобки — квантификатор {3} будет распространяться только на букву «g».
Так же можно применять квантификаторы с классами символов:
Квантификатор {3} распространяет действие на класс символов в скобках в первом примере, а во втором — только на символ «c».
Первый пример использует жадный квантификатор .* для поиска любого символа, 0 или более раз, за которым расположены символы "f" "o" "o". Так как кантификатор жадный — найденное совпадение содержит всю строку. Жадный квантификатор не найдет все совпадения в строке, т.к. на первом шаге, просмотрев всю строку, он найдет совпадение и закончит работу.
Второй пример — ленивый и начинает с начала строки, добавляя символ за символом. Начинается работа программы с проверки «пустоты», но т.к. последовательности «foo» нет в начале строки, поиск продолжается с добавление символа «x», после которого будет найдено первое совпадение между индексами 0 и 4. Поиск продолжается до конца строки и второе совпадение будет найдено между индексами 4 и 13.
Третий пример не находит совпадений потому что квантификатор ревнивый. В этом случае регулярное выражение .*+ «съело» всю строку не оставив ничего для «foo». Используйте ревнивый квантификатор, когда нужно отбросить все не нужное в строке, он будет эффективнее эквивалентного жадного квантификатора.
На этом всё!
Ссылка на первоисточник: Основы регулярных выражений в Java. Часть 3

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

\d
означает цифру (0-9), \w
означает любую заглавную или прописную букву, символ подчеркивания или цифру). Используйте предопределенные классы символов, где это возможно. Это сделает ваш код проще для чтения и исправления ошибок.
Конструкции, начинающиеся с обратного слеша, называются экранированными или защищенными. В предыдущих статьях мы уже говорили об экранировании специальных символов обратным слешем или символами \Q
и \E
для использования их в качестве обычных символов. Если вы используете обратный слеш с обычными символами (литералами), то необходимо экранировать этот бэк слеш, чтобы выражение скомпилировалось.
private final String REGEX = "\\d"; // цифра
В этом примере \d
— регулярное выражение; дополнительный обратный слеш необходим для того, чтобы программа скомпилировалась. Наша тестовая программа читает регулярные выражения прямо из консоли, поэтому дополнительный слеш не нужен.
Следующий пример демонстрирует использование предопределенных символьных классов:


.
» (специальный символ точка), что означает любой символ. Поэтому поиск был успешным во всех случаях. В других примерах используются предопределенные символьные классы, значения которых мы рассмотрели в таблице выше.
Квантификаторы

Совпадения нулевой длины
Начнем с жадного. Напишем три разных регулярных выражения: буква «a» со специальными символами ?, * или +. Посмотрим, что произойдет если тестировать эти регулярки на пустой строке:





Enter your regex: a{3,}
Enter input string to search: aaaaaaaaa
I found the text "aaaaaaaaa" starting at index 0 and ending at index 9.
В этом примере программа находит только одно совпадение, потому что строка удовлетворяет требованию минимальной длины последовательности (3) символов «a».
Наконец, задание максимальной длины последовательности:

Использование групп символов и классов с квантификаторами
До этого момента мы тестировали квантификаторы на строках, содержащих один и тот же символ. Квантификаторы распространяют свое действие только на один символ, поэтому регулярное выражение «abc+» будет находить стоки содержащие «ab» и «c» один или более раз. Оно не будет означать «abc» один или более раз. Но квантификаторы могут применяться вместе с группами и классами символов, например, [abc]+ (a или b или c, один или более раз) или (abc)+ («abc» один или более раз). Найдем группу символов (dog), три раза в строке:

Различия жадных, ленивых и сверхжадных квантификаторов
Есть небольшие различия между жадными (greedy), ленивыми (reluctant) и ревнивыми (possessive) квантификаторами. Жадные квантификаторы названы так, потому что пытаются найти максимально длинное совпадение: сначала программа пытается «съесть» всю строку, если совпадение не найдено, то отбрасывается один символ и поиск повторяется, пока не будет найдено совпадение или не останется больше символов. Ленивые — наоборот, начинают с начала строки, добавляя символ за символом, пока не найдут совпадение. Наконец, ревнивая квантификация просматривает сразу всю строку единожды, не убирая символы, как в жадной. Для демонстрации будем использовать строку xfooxxxxxxfoo.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ