Matches: примеры (JAVA)

Разбор метода matches в Java
Раздел: Верификация (валидация), Регулярные выражения
matches(String regex): boolean

Общее описание метода matches

В Java метод matches применяется для проверки соответствия строки регулярному выражению. Наиболее часто используется как:

  • String.matches(String regex) - метод класса java.lang.String;
  • Pattern.matches(String regex, CharSequence input) - статический метод класса java.util.regex.Pattern;
  • Matcher.matches() - метод экземпляра java.util.regex.Matcher.

Ключевая особенность: все перечисленные варианты проверяют соответствие всей входной строки шаблону. Для поиска подстроки служат другие методы, например Matcher.find().

Аргументы и возвращаемые значения:

  • String.matches(String regex): принимает один аргумент regex (регулярное выражение в виде строки). Возвращает boolean - true, если вся строка соответствует шаблону, иначе false. При неверном синтаксисе регулярного выражения выбрасывается PatternSyntaxException.
  • Pattern.matches(String regex, CharSequence input): принимает шаблон и входную последовательность символов. Эквивалентен Pattern.compile(regex).matcher(input).matches(). Возвращает boolean.
  • Matcher.matches(): вызывается для уже скомпилированного шаблона (Pattern) и проверяет совпадение всего текста, возвращает boolean. Полезен, когда требуется использовать флаги или повторно применять компилированный шаблон.

Флаги и модификаторы регулярных выражений применяются через Pattern.compile(regex, flags) или через встроенные модификаторы ((?i) для игнорирования регистра, (?s) для DOTALL и т. п.). Строковый метод String.matches не принимает флаги напрямую.

Особенности поведения:

  • Метод проверяет полное совпадение, поэтому шаблон \d+ для строки "12ab" вернёт false, а для "123" вернёт true.
  • При необходимости частичного поиска стоит использовать Pattern и Matcher.find() или шаблон с явными подшаблонами, например .*pattern.* для приведения к полному совпадению.

Короткие примеры использования

Несколько простых примеров с кодом и ожидаемым результатом.

// Пример 1: String.matches
String s1 = "abc123";
boolean r1 = s1.matches("[a-z]+\\d+");
System.out.println(r1);
true
// Пример 2: Pattern.matches эквивалент
boolean r2 = java.util.regex.Pattern.matches("\\d+", "42");
System.out.println(r2);
true
// Пример 3: Matcher.matches против find
java.util.regex.Pattern p = java.util.regex.Pattern.compile("cat");
java.util.regex.Matcher m = p.matcher("concatenate");
System.out.println(m.matches());
System.out.println(m.find());
false
true
// Пример 4: Флаги через Pattern.compile
java.util.regex.Pattern p2 = java.util.regex.Pattern.compile("hello", java.util.regex.Pattern.CASE_INSENSITIVE);
System.out.println(p2.matcher("HeLlO").matches());
true

Похожие инструменты в Java

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

  • Matcher.find() - ищет частичное совпадение внутри текста. Предпочтительнее при поиске подстроки.
  • Matcher.lookingAt() - проверяет совпадение с начала строки, но не обязательно до конца. Полезно при проверке префикса.
  • String.contains и indexOf - для простого поиска подстроки без регулярных выражений; работают быстрее и проще при точном совпадении последовательности символов.
  • Pattern.compile(...) + matcher - предпочтительно при многократном использовании одного шаблона (экономия на компиляции) и при необходимости флагов.

Выбор зависит от задачи: для полного соответствия использовать matches, для поиска подстроки - find, для проверки префикса - lookingAt, для простого поиска без regex - contains/indexOf.

Альтернативы в других языках

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

  • JavaScript: /pattern/.test(str) или RegExp.prototype.test. По умолчанию ищет соответствие подстроки. Для проверки полного совпадения требуется якорь ^...$.
    /^\d+$/.test('123')
    true
  • Python: re.fullmatch(pattern, string) проверяет полное совпадение (аналог String.matches), а re.search находит подстроку.
    import re
    print(bool(re.fullmatch(r"\d+", "42")))
    True
  • PHP: preg_match('/pattern/', $str) возвращает числа совпадений; по умолчанию ищет подстроку, для полного совпадения нужен ^...$.
    <?
    var_dump(preg_match('/^\\d+$/', '42'));
    ?>
    int(1)
  • C#: Regex.IsMatch(input, pattern) по умолчанию ищет подстроку; для полного соответствия добавить якоря или использовать ^...$.
    using System.Text.RegularExpressions;
    Console.WriteLine(Regex.IsMatch("123", "^\\d+$"));
    True
  • Go: regexp.MatchString(pattern, s) ищет соответствие подстроки; для полного совпадения нужны якоря.
    package main
    import (
      "fmt"
      "regexp"
    )
    func main(){
      fmt.Println(regexp.MatchString("^\\\d+$", "42"))
    }
    true 
  • Kotlin: String.matches(Regex) проверяет всю строку, аналогично Java String.matches. Также есть Regex.containsMatchIn для поиска подстроки.
    println("abc".matches(Regex("[a-z]+")))
    true
  • Lua: string.match использует упрощенные шаблоны Lua, отличающиеся от PCRE/Java regex; для сложных regex требуется внешняя библиотека.
  • SQL: разные СУБД предоставляют разные возможности: LIKE для простых шаблонов, в MySQL есть REGEXP для регулярных выражений, но синтаксис и поведение могут отличаться от Java.

Главные отличия: в Java String.matches требует полного совпадения; в некоторых языках методы по умолчанию ищут подстроку. Также поддержка флагов и синтаксиса регулярных выражений варьируется.

Типичные ошибки при использовании

  • Ожидание частичного совпадения при использовании String.matches. Пример:
    System.out.println("hello world".matches("world"));
    false
    Объяснение: метод требует совпадения всей строки; для поиска подстроки использовать .*world.* или Matcher.find().
  • Неправильное экранирование обратных слэшей в строковых литералах. Пример:
    System.out.println("\"\\d+\"".matches("\\d+")); // неверное использование
    false
    Правильно: s.matches("\\\d+"), где каждый обратный слэш в regex требует двойного экранирования в Java-строке.
  • Игнорирование исключений синтаксиса шаблона. Пример:
    String regex = "([0-9]";
    System.out.println("123".matches(regex));
    Exception in thread "main" java.util.regex.PatternSyntaxException: Unclosed group
  • Повторная компиляция шаблона в цикле, что ведет к ухудшению производительности. Предпочтительнее закомпилировать Pattern один раз и переиспользовать Matcher.
  • Неправильное использование флагов: String.matches не принимает флаги; для флагов требуется Pattern.compile(..., flags).

Изменения и развитие поддержки

За последние релизы Java не было радикальных изменений в поведении метода matches как такового. Изменения касаются двигателя регулярных выражений в целом:

  • Периодические обновления поддержки стандартов Unicode в Java приводят к изменениям в поведенческих характеристиках классов Pattern и Matcher при работе с символьными классами.
  • Добавление и улучшение синтаксиса регулярных выражений происходило раньше (например, именованные группы доступны в современных версиях). Важно проверять совместимость конкретных флагов и расширений с используемой версией JVM.
  • Оптимизации производительности движка regex проводятся постепенно, однако API сохраняет обратную совместимость.

Расширенные примеры и подходы

Подробные варианты применения с пояснениями.

Пример java
// 1. Валидация email (простая проверка)
String email = "user.name+tag@example.co.uk";
String emailRegex = "(?i)^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$"; // (?i) - флаг игнорирования регистра
System.out.println(email.matches(emailRegex));
true

Пояснение: для более строгой валидации требуется более сложный шаблон; данный пример показывает использование встроенного модификатора (?i).

Пример java
// 2. Использование именованных групп и извлечение данных
java.util.regex.Pattern p = java.util.regex.Pattern.compile("(?\\d{3})-(?\\d{4})");
java.util.regex.Matcher m = p.matcher("123-4567");
if (m.matches()) {
  System.out.println(m.group("area"));
  System.out.println(m.group("local"));
}
123
4567

Пояснение: именованные группы удобны для читаемости и получения данных по имени вместо номера группы.

Пример java
// 3. Повторное использование Pattern для производительности
java.util.regex.Pattern datePattern = java.util.regex.Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
String[] values = {"2020-01-01", "not a date", "1999-12-31"};
for (String v : values) {
  System.out.println(v + " -> " + datePattern.matcher(v).matches());
}
2020-01-01 -> true
not a date -> false
1999-12-31 -> true
Пример java
// 4. Многострочный и DOTALL режимы
String text = "first line\nsecond line";
// (?s) включает DOTALL: точка совпадает с символом перевода строки
System.out.println(text.matches("(?s).*second.*"));
// (?m) включает MULTILINE: ^ и $ работают по-строчно
System.out.println(text.matches("(?m)^second.*$"));
true
false

Пояснение: первый пример ищет подстроку, включая перевод строки. Второй пытается сопоставить всю строку с шаблоном, начинающимся с "second", поэтому возвращается false.

Пример java
// 5. Использование lookahead для условий
String s = "abc123";
System.out.println(s.matches("(?=.*\\d)(?=.*[a-zA-Z]).+")); // проверка, что есть и буквы, и цифры
true

Пояснение: положительные lookahead позволяют описать комплексные условия без захвата частей строки.

Пример java
// 6. Замены с обратными ссылками
String date = "2020/12/31";
System.out.println(date.replaceAll("(\\d{4})/(\\d{2})/(\\d{2})", "$3.$2.$1"));
31.12.2020

Пояснение: после проверки соответствия часто следует прямая замена с использованием групп.

Пример java
// 7. Предотвращение ReDoS: использование жадных и ленивых квантификаторов аккуратно
String evil = "aaaaaaaaaaaaaaaaaaaaaaaa!";
// опасный шаблон, приводящий к долгой обработке при определённых входных данных
String dangerous = "^(a+)+!$";
System.out.println(evil.matches(dangerous)); // может быть медленно
// безопаснее: использовать ограничение на длину или альтернативы
String safer = "^(?:a{1,100})+!$";
System.out.println(evil.matches(safer));
false
false

Пояснение: при проектировании выражений важно учитывать потенциальные атаки на регулярные выражения и ограничивать ввод или структуру шаблонов.

джава matches function comments

En
Matches Tells whether or not this string matches the given regular expression