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

Разница между Java Matcher find() и match()

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

1. Обзор

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

Как правило, мы почти всегда хотим использовать один из двух популярных методов класса Matcher :

  • найти()
  • Спички()

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

2. Метод find ()

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

Давайте представим, что мы хотим найти в предоставленной строке «до свидания 2019 и добро пожаловать 2020» только четырехзначные числа.

Для этого мы будем использовать шаблон «\\d\\d\\d\\d» :

@Test
public void whenFindFourDigitWorks_thenCorrect() {
Pattern stringPattern = Pattern.compile("\\d\\d\\d\\d");
Matcher m = stringPattern.matcher("goodbye 2019 and welcome 2020");

assertTrue(m.find());
assertEquals(8, m.start());
assertEquals("2019", m.group());
assertEquals(12, m.end());

assertTrue(m.find());
assertEquals(25, m.start());
assertEquals("2020", m.group());
assertEquals(29, m.end());

assertFalse(m.find());
}

Поскольку в этом примере у нас есть два вхождения — 2019 и 2020 , — метод find() дважды вернет true , а как только он достигнет конца области совпадения, он вернет false .

Как только мы найдем какое-либо совпадение, мы можем использовать такие методы, как start() , group() и end() , чтобы получить более подробную информацию о совпадении , как показано выше.

Метод start() даст начальный индекс совпадения, end() вернет последний индекс символа после окончания совпадения, а group() вернет фактическое значение совпадения .

3. Метод find (int)

Также у нас есть перегруженная версия метода find — find(int) . Он принимает начальный индекс в качестве параметра и рассматривает начальный индекс как отправную точку для поиска вхождений в строке .

Давайте посмотрим, как использовать этот метод на том же примере, что и раньше:

@Test
public void givenStartIndex_whenFindFourDigitWorks_thenCorrect() {
Pattern stringPattern = Pattern.compile("\\d\\d\\d\\d");
Matcher m = stringPattern.matcher("goodbye 2019 and welcome 2020");

assertTrue(m.find(20));
assertEquals(25, m.start());
assertEquals("2020", m.group());
assertEquals(29, m.end());
}

Поскольку мы предоставили начальный индекс 20 , мы видим, что теперь найдено только одно вхождение — 2020, которое, как и ожидалось, происходит после этого индекса . И, как и в случае с find() , мы можем использовать такие методы, как start() , group() и end() , чтобы извлечь больше деталей о совпадении.

4. Метод match ()

С другой стороны, методmatches () пытается сопоставить всю строку с шаблоном .

Для того же примера match() вернет false :

@Test
public void whenMatchFourDigitWorks_thenFail() {
Pattern stringPattern = Pattern.compile("\\d\\d\\d\\d");
Matcher m = stringPattern.matcher("goodbye 2019 and welcome 2020");

assertFalse(m.matches());
}

Это связано с тем, что он попытается сопоставить «\\d\\d\\d\\d» со всей строкой « прощай, 2019 и добро пожаловать, 2020»в отличие от методов find() и find(int) , оба из которых найти вхождение шаблона в любом месте строки .

Если мы изменим строку на четырехзначное число «2019» , тогда match() вернет true :

@Test
public void whenMatchFourDigitWorks_thenCorrect() {
Pattern stringPattern = Pattern.compile("\\d\\d\\d\\d");
Matcher m = stringPattern.matcher("2019");

assertTrue(m.matches());
assertEquals(0, m.start());
assertEquals("2019", m.group());
assertEquals(4, m.end());
assertTrue(m.matches());
}

Как показано выше, мы также можем использовать такие методы, как start() , group() и end() , чтобы собрать больше деталей о совпадении. Следует отметить один интересный момент: многократный вызов find() может возвращать разные выходные данные после вызова этих методов, как мы видели в нашем первом примере, но match() всегда будет возвращать одно и то же значение.

5. Разница между matcher() и Pattern.matches()

Как мы видели в предыдущем разделе, метод matcher() возвращает Matcher , который сопоставляет заданный ввод с шаблоном.

С другой стороны, Pattern.matches() — это статический метод, который компилирует регулярное выражение и сопоставляет с ним весь ввод .

Давайте создадим тестовые примеры, чтобы подчеркнуть разницу:

@Test
public void whenUsingMatcher_thenReturnTrue() {
Pattern pattern = Pattern.compile(REGEX);
Matcher matcher = pattern.matcher(STRING_INPUT);

assertTrue(matcher.find());
}

Короче говоря, когда мы используем matcher() , мы задаем вопрос: содержит ли строка шаблон?

А с помощью Pattern.matches() мы спрашиваем: является ли строка шаблоном?

Давайте посмотрим на это в действии:

@Test
public void whenUsingMatches_thenReturnFalse() {
assertFalse(Pattern.matches(REGEX, STRING_INPUT));
}

Так как Pattern.matches() пытается сопоставить всю строку, она возвращает false .

6. Заключение

В этой статье мы увидели, как find() , find(int) иmatch () отличаются друг от друга на практическом примере. Мы также видели, как различные методы, такие как start() , group() и end() , могут помочь нам извлечь больше деталей о заданном совпадении .

Как всегда, полный исходный код статьи доступен на GitHub .