Різниця між матчами () та знахідкою () у Java Regex


250

Я намагаюся зрозуміти різницю між matches()і find().

За словами Javadoc, (з того, що я розумію), здійснить matches()пошук по всій рядку, навіть якщо знайде те, що шукає, і find()зупиниться, коли знайде те, що шукає.

Якщо це припущення правильне, я не бачу, коли ви хочете використовувати його matches()замість find(), якщо ви не хочете порахувати кількість збігів, які він знайде.

На мою думку, клас String тоді повинен мати find()замість matches()вбудованого методу.

Отже, підсумовуючи:

  1. Чи правильне моє припущення?
  2. Коли корисно використовувати matches()замість find()?

2
Пам’ятайте, що виклик find()кілька разів може призвести до різних результатів для одних і тих же Matcher. Дивіться мою відповідь нижче.
L. Holanda

Відповіді:


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()завжди буде повертатися однаковий результат. Дивіться мою відповідь нижче.
L. Holanda

80

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


35
Можна сказати, що matches(p)це те саме, як find("^" + p + "$")якщо б це було зрозуміліше.
jensgram

4
Наведемо лише приклад для уточнення відповіді: "[az] +" із рядком "123abc123" не вдасться використати сірники (), але вдасться з використанням find ().
bezmax

3
@Max Точно, "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()
AlexR

3
@AlexR / @jensgram: ...("some pattern").matcher(str).matches()це НЕ в точності так само ...("^some pattern$").matcher(str).find()це тільки істинним в першому виклику. Дивіться мою відповідь нижче.
L. Holanda

62

matches()поверне істину лише в тому випадку, якщо повний рядок буде збігатися. 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
Знайдено: помилково
Знайдено: помилково
Збіг: хибний
-----------
Знайдено: вірно - позиція 0
Знайдено: помилково
Знайдено: помилково
Збіг: правда
Збіг: правда
Збіг: правда
Збіг: правда

Отже, будьте обережні при виклику find()декількох разів, якщо Matcherоб'єкт не було скинуто, навіть коли регулярний вираз оточений ^і $відповідає цілому рядку.


2
дуже корисний товариш
DockYard

6

find()буде розглядати підрядку проти регулярного виразу, де, як і, matches()буде розглянуто повний вираз.

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

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]щоб знайти принаймні один збіг. Якщо такий збіг знайдений, він буде індексований, тоді цикл буде виконуватися на основі індексований результат в іншому випадку, якщо він не зробив попереднього обчислення, як, наприклад matches(), ні. Оператор while ніколи не буде виконуватись, оскільки перший символ зіставленого рядка не є алфавітом.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.