RegExp capturing groups



В этом посте расскажу про группы в регулярках и покажу, как извлечь данные из текста без лишней суеты.



Базовый синтаксис регулярных выражений можно почитать, например, в этой статье с кучей картинок. Группы — это уже уровень intermediate:)



Допустим, есть строка src:

Stack: Java 17, Spring Boot 2.7.1



Наша задача — вытащить отсюда версию джавы.



Этап 1. Начнём с простого варианта:



String p = "Java\\s\\d+";

Matcher m = Pattern.compile(p).matcher(src);

if (m.find()) {

res = m.group(); // Java 17

}

String version = res.substring(5); // 17



Этап 2: подключаем группы. В паттерн добавляются скобки



String p = "Java\\s(\\d+)";



После m.find() получаем следующее:

▫️ m.group() или m.group(0) → Java 17. В нулевой группе всегда содержится целиком найденное выражение

▫️ m.group(1) → 17



Получаем сразу версию, и substring нам больше не нужен😎



Пример посложнее. Из строки

Stack: Java 17, Spring Boot 2.7

нужно извлечь версию java и spring boot. Сделаем паттерн по аналогии:



String p = "Java\\s(\\d+).+Boot\\s(\\d+\\.\\d+)";



Здесь два выражения в скобках и, соответственно, две группы (помимо нулевой):



if (m.find()) {

javaVersion = m.group(1)); // 17

bootVersion = m.group(2); // 2.7

}



Чтобы сделать код более читаемым, дадим группам имена. Вот так:

(?<name>X)

Где name — имя, X — регулярка.



Теперь обновляем паттерн

String p = "Java\\s(?<java>\\d+).+Spring\\sBoot\\s(?<boot>\\d+\\.\\d+)";



Извлекаем версии

javaVersion = m.group("java");

bootVersion = m.group("boot");



Готово! Без групп пришлось бы использовать два паттерна и всякие методы с индексами, а с группами получился лаконичный и понятный код👌