Перейти к основному содержимому

Как подсчитать количество совпадений для регулярного выражения?

· 3 мин. чтения

1. Обзор

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

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

2. Вариант использования

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

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

([a-z0-9_.-]+)@([a-z0-9_.-]+[a-z])

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

Нам понадобится это регулярное выражение внутри объекта Pattern , чтобы мы могли его использовать:

Pattern EMAIL_ADDRESS_PATTERN = 
Pattern.compile("([a-z0-9_.-]+)@([a-z0-9_.-]+[a-z])");

Мы рассмотрим два основных подхода, один из которых зависит от использования Java 9 или более поздней версии.

Для нашего примера текста мы попытаемся найти три письма в строке:

"You can contact me through writer@foreach.com, editor@foreach.com, and team@bealdung.com"

3. Подсчет совпадений для Java 8 и старше

Во-первых, давайте посмотрим, как подсчитывать совпадения с использованием Java 8 или старше.

Простой способ подсчета совпадений состоит в повторении метода find класса Matcher . Этот метод пытается найти следующую подпоследовательность входной последовательности, которая соответствует шаблону :

Matcher countEmailMatcher = EMAIL_ADDRESS_PATTERN.matcher(TEXT_CONTAINING_EMAIL_ADDRESSES);

int count = 0;
while (countEmailMatcher.find()) {
count++;
}

Используя этот подход, мы найдем три совпадения, как и ожидалось:

assertEquals(3, count);

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

Например, давайте рассмотрим этот пример:

String OVERLAPPING_EMAIL_ADDRESSES = "Try to contact us at team@foreach.comeditor@foreach.com, support@foreach.com.";

Matcher countOverlappingEmailsMatcher = EMAIL_ADDRESS_PATTERN.matcher(OVERLAPPING_EMAIL_ADDRESSES);

int count = 0;
while (countOverlappingEmailsMatcher.find()) {
count++;
}

assertEquals(2, count);

Когда регулярное выражение пытается найти совпадения в заданной строке , сначала оно найдет совпадение « team@foreach.comeditor ». Поскольку перед @ нет части домена, маркер не будет сброшен, а второй «@foreach.com» будет проигнорирован. Двигаясь дальше, он также будет рассматривать « support@foreach.com » как второе совпадение:

./ebc2e8a3029894140c94bdc72cb87154.png

Как показано выше, у нас есть только два совпадения в примере с перекрывающимся электронным письмом.

4. Подсчет совпадений для Java 9 и более поздних версий

Однако, если у нас есть более новая версия Java, мы можем использовать метод results класса Matcher . Этот метод, добавленный в Java 9, возвращает последовательный поток результатов совпадений, что упрощает подсчет совпадений:

long count = countEmailMatcher.results()
.count();

assertEquals(3, count);

Как мы видели с find , Matcher не сбрасывается при обработке потока из метода results . Точно так же метод результатов не будет работать для поиска перекрывающихся совпадений.

5. Вывод

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

Во-первых, мы узнали, как использовать метод find с циклом while . Затем мы увидели, как новый метод потоковой передачи Java 9 позволяет нам делать это с меньшим количеством кода.

Как всегда, образцы кода доступны на GitHub .