Понимаем и используем группы захвата в Java regex
Быстрый ответ
При создании групп захвата в регулярных выражениях Java используйте круглые скобки "(\d+)-(\w+)"
, чтобы определить две группы: для чисел (\d+)
и букв (\w+)
. Обработка данных групп происходит через классы Pattern
и Matcher
:
Pattern pattern = Pattern.compile("(\\d+)-(\\w+)");
Matcher matcher = pattern.matcher("123-abc");
if (matcher.find()) {
String digits = matcher.group(1); // 123 — ...захвачено!
String letters = matcher.group(2); // "abc" — ...успешно захвачено!
}
Отметим, что matcher.group(1)
и matcher.group(2)
возвращают содержимое соответствующих групп.
Разбираемся с квантификаторами и способами захвата
Квантификаторы: жадные, ленивые и ревнивые типы
Квантификаторы определяют, сколько символов, соответствующих шаблону, надо захватить:
- Жадные (
*
): пытаются захватывать максимальное количество символов. - Ленивые (
*?
): стремятся захватить минимальное количество символов. - Ревнивые (
*+
): работают аналогично жадным, но не допускают возврата.
Тип квантификатора определяет способ действия группы захвата в выражении.
Принцип "слева направо"
Порядок обработки и захвата регулярных выражений происходит слева направо. Так, первая группа будет захвачена раньше второй и так далее.
Обратные ссылки и именованные группы
Обратные ссылки (\1
, \2
и т.д.) позволяют сослаться на уже захваченные группы. В версиях Java 7 и выше доступна возможность использования именованных групп посредством (?<name>...)
, что улучшает читабельность кода.
Обеспечение точного соответствия
Незахватывающие группы
Незахватывающие группы (?:...)
позволяют применить квантификаторы, не захватывая содержимое.
Три основных строительных блока
Точка (.), звёздочка (*), и плюс (+) используются для обозначения различных комбинаций символов в регулярных выражениях.
Крайние случаи
Следует учесть такие экстремальные ситуации как совпадения нулевой длины, перекрывающиеся совпадения и ошибочные захваты.
Визуализация
Для наглядного представления работы регулярных выражений удобно использовать аналогию с "отрядом захватчиков":
Отряд: [Командир, Группа 1 (Рейдер), Группа 2 (Собиратель), ..., Запасной]
Каждый член отряда отвечает за захват определённых шаблонов:
Pattern.compile("(Рейдер)(:)(\\d+)");
Отчет о захвате:
🦸♀️🎁📦: [Рейдер, ":", "12345"]
Дополнительные сценарии
Захват определённых данных
Чтобы извлечь расширения файлов, используем шаблон (\w+)\.(\w+)
:
Pattern p = Pattern.compile("(\\w+)\\.(\\w+)");
Matcher m = p.matcher("masterpiece.png");
if (m.find()) {
String baseName = m.group(1);
String ext = m.group(2);
}
Работа с опциональными элементами
Опциональные шаблоны описываются посредством (pattern)?
:
Pattern p = Pattern.compile("ОЙ, (\\w+)(, приятель)?");
Matcher m = p.matcher("ОЙ, Брюс, приятель");
if (m.find()) {
String name = m.group(1);
String optional = m.group(2);
}
Группировка сложных форматов
Для работы с датами и другими сложными форматами выражений можно применять следующую конструкцию:
Pattern p = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher m = p.matcher("2099-12-31");
if (m.find()) {
String year = m.group(1);
String month = m.group(2);
String day = m.group(3);
}
Полезные материалы
Ссылки на дополнительные ресурсы по регулярным выражениям в Java и работе с классами Pattern
и Matcher
.