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 .