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


250

Я пытаюсь понять разницу между matches()и find().

Согласно Javadoc, (из того, что я понимаю), matches()будет искать всю строку, даже если он найдет то, что ищет, и find()остановится, когда найдет то, что ищет.

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

По моему мнению, класс String должен иметь find()вместо matches()встроенного метода.

Итак, подведем итог:

  1. Правильно ли мое предположение?
  2. Когда это полезно использовать matches()вместо find()?

2
Имейте в виду, что вызов find()несколько раз может вернуть разные результаты для одного и того же Matcher. Смотрите мой ответ ниже.
Л. Холанда

Ответы:


300

matchesпытается сопоставить выражение со всей строкой и неявно добавить a ^в начале и $в конце вашего шаблона, то есть он не будет искать подстроку. Отсюда вывод этого кода:

public static void main(String[] args) throws ParseException {
    Pattern p = Pattern.compile("\\d\\d\\d");
    Matcher m = p.matcher("a123b");
    System.out.println(m.find());
    System.out.println(m.matches());

    p = Pattern.compile("^\\d\\d\\d$");
    m = p.matcher("123");
    System.out.println(m.find());
    System.out.println(m.matches());
}

/* output:
true
false
true
true
*/

123является подстрокой, a123bпоэтому find()метод выводит true. matches()только «видит», a123bкоторый не совпадает 123и, следовательно, выводит ложь.


25
Этот ответ вводит в заблуждение. matchers()это не просто find()подразумеваемое окружение ^ и $. Помните, что вызов .find()более одного раза может иметь разные результаты, если ему не предшествует reset(), а matches()всегда будет возвращать один и тот же результат. Смотрите мой ответ ниже.
Л. Холанда

80

matchesвернуть true, если вся строка соответствует заданному шаблону. findпытается найти подстроку, которая соответствует шаблону.


35
Вы могли бы сказать, что matches(p)это так же, как find("^" + p + "$")если бы это было немного яснее.
jensgram

4
Просто пример, поясняющий ответ: «[az] +» со строкой «123abc123» завершится неудачно с помощью match (), но преуспеет с помощью find ().
bezmax

3
@ Макс Точно, "123abc123".matches("[a-z]+")потерпит неудачу, как и раньше "123abc123".find("^[a-z]+$"). Моя точка зрения состояла в том, что это matches()подходит для полного матча, так же как find()с начальным и конечным якорями.
jensgram

5
Pattern.compile("some pattern").matcher(str).matches()Pattern.compile("^some pattern$").matcher(str).find()
невероятно похож

3
@AlexR / @jensgram: ...("some pattern").matcher(str).matches()это не в точности равно ...("^some pattern$").matcher(str).find()это только истинным в первом вызове. Смотрите мой ответ ниже.
Л. Холанда

62

matches()вернет true, только если найдена полная строка. find()попытается найти следующее вхождение в подстроке, которая соответствует регулярному выражению. Обратите внимание на акцент на «следующий». Это означает, что результат вызова find()несколько раз может не совпадать. Кроме того, с помощью find()вы можете вызвать, start()чтобы вернуть позицию, в которой подстрока была найдена.

final Matcher subMatcher = Pattern.compile("\\d+").matcher("skrf35kesruytfkwu4ty7sdfs");
System.out.println("Found: " + subMatcher.matches());
System.out.println("Found: " + subMatcher.find() + " - position " + subMatcher.start());
System.out.println("Found: " + subMatcher.find() + " - position " + subMatcher.start());
System.out.println("Found: " + subMatcher.find() + " - position " + subMatcher.start());
System.out.println("Found: " + subMatcher.find());
System.out.println("Found: " + subMatcher.find());
System.out.println("Matched: " + subMatcher.matches());

System.out.println("-----------");
final Matcher fullMatcher = Pattern.compile("^\\w+$").matcher("skrf35kesruytfkwu4ty7sdfs");
System.out.println("Found: " + fullMatcher.find() + " - position " + fullMatcher.start());
System.out.println("Found: " + fullMatcher.find());
System.out.println("Found: " + fullMatcher.find());
System.out.println("Matched: " + fullMatcher.matches());
System.out.println("Matched: " + fullMatcher.matches());
System.out.println("Matched: " + fullMatcher.matches());
System.out.println("Matched: " + fullMatcher.matches());

Будет выводить:

Найдено: ложь
Найдено: правда - позиция 4
Найдено: правда - позиция 17
Найдено: правда - позиция 20
Найдено: ложь
Найдено: ложь
Подходящий: ложный
-----------
Найдено: true - позиция 0
Найдено: ложь
Найдено: ложь
Подходит: правда
Подходит: правда
Подходит: правда
Подходит: правда

Поэтому будьте осторожны при find()многократном вызове, если Matcherобъект не был сброшен, даже когда регулярное выражение окружено ^и $соответствует полной строке.


2
очень полезный друг
DockYard

6

find()будет рассматривать подстроку против регулярного выражения, где as matches()будет считать полное выражение.

find() возвращает true, только если подстрока выражения соответствует шаблону.

public static void main(String[] args) {
        Pattern p = Pattern.compile("\\d");
        String candidate = "Java123";
        Matcher m = p.matcher(candidate);

        if (m != null){
            System.out.println(m.find());//true
            System.out.println(m.matches());//false
        }
    }

3

matches();не буферизует, но find()буферизирует. find()сначала выполняет поиск в конце строки, индексирует результат и возвращает логическое значение и соответствующий индекс.

Вот почему, когда у вас есть такой код

1:Pattern.compile("[a-z]");

2:Pattern.matcher("0a1b1c3d4");

3:int count = 0;

4:while(matcher.find()){

5:count++: }

На этапе 4: механизм регулярных выражений, использующий структуру шаблона, прочитает весь ваш код (от индекса к индексу, как указано в параметре, regex[single character]чтобы найти хотя бы одно совпадение. Если такое совпадение найдено, оно будет проиндексировано, тогда цикл будет выполняться на основе индексированный результат else, если он не выполнял предварительное вычисление, например, который matches()не делает. Оператор while никогда не будет выполнен, поскольку первый символ совпадающей строки не является алфавитом.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.