Różnica między dopasowaniami () i find () w Java Regex

249

Próbuję zrozumieć różnicę między matches()i find().

Według Javadoc (z tego, co rozumiem) matches()przeszuka cały ciąg, nawet jeśli znajdzie to, czego szuka, i find()zatrzyma się, gdy znajdzie to, czego szuka.

Jeśli to założenie jest prawidłowe, nie widzę, kiedy chcesz użyć matches()zamiast find(), chyba że chcesz policzyć liczbę znalezionych przez niego dopasowań.

Moim zdaniem klasa String powinna mieć find()zamiast tego matches()wbudowaną metodę.

Podsumowując:

  1. Czy moje założenie jest prawidłowe?
  2. Kiedy warto używać matches()zamiast find()?
Shervin Asgari
źródło
2
Pamiętaj, że find()wielokrotne dzwonienie może zwrócić różne wyniki dla tego samego Matcher. Zobacz moją odpowiedź poniżej.
L. Holanda,

Odpowiedzi:

300

matchespróbuje dopasować wyrażenie do całego łańcucha i niejawnie dodać ^na początku i $na końcu wzorca, co oznacza, że ​​nie będzie szukał podłańcucha. Stąd wynik tego kodu:

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
*/

123jest podciągiem, a123bwięc find()metoda zwraca true. matches()tylko „widzi”, a123bco nie jest tym samym, co daje wynik 123fałszywy.

Sanjay T. Sharma
źródło
25
Ta odpowiedź jest myląca. matchers()nie jest po prostu find()domniemanym otoczeniem ^ i $. Pamiętaj, że dzwonienie .find()więcej niż jeden raz może mieć inne wyniki, jeśli nie zostanie poprzedzone reset(), a matches()zawsze zwróci ten sam wynik. Zobacz moją odpowiedź poniżej.
L. Holanda,
80

matcheszwraca true, jeśli cały łańcuch pasuje do podanego wzorca. findpróbuje znaleźć podciąg pasujący do wzorca.

Chaczik
źródło
35
Można powiedzieć, że matches(p)to tak samo, find("^" + p + "$")jakby to było bardziej zrozumiałe.
jensgram
4
Tylko przykład, aby wyjaśnić odpowiedź: „[az] +” z ciągiem „123abc123” nie powiedzie się przy użyciu dopasowania (), ale odniesie sukces przy użyciu find ().
bezmax,
3
@Max Dokładnie, "123abc123".matches("[a-z]+")zawiedzie tak samo jak "123abc123".find("^[a-z]+$"). Chodzi mi o to, że matches()chodzi o pełne dopasowanie, tak jak w find()przypadku kotwic początkowych i końcowych.
jensgram,
5
Pattern.compile("some pattern").matcher(str).matches()jest równyPattern.compile("^some pattern$").matcher(str).find()
AlexR
3
@AlexR / @jensgram: nie...("some pattern").matcher(str).matches() jest dokładnie równy, co jest prawdziwe tylko w pierwszym wywołaniu. Zobacz moją odpowiedź poniżej. ...("^some pattern$").matcher(str).find()
L. Holanda,
62

matches()zwróci true, tylko jeśli pełny ciąg jest dopasowany. find()spróbuje znaleźć następne wystąpienie w podciągu pasującym do wyrażenia regularnego. Zwróć uwagę na nacisk na „następny”. Oznacza to, że find()wielokrotne wywołanie może nie być takie samo. Ponadto za pomocą find()można wywołać, start()aby zwrócić pozycję, do której dopasowano podciąg.

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());

Wyjdzie:

Znaleziono: fałsz
Znaleziono: prawda - pozycja 4
Znaleziono: prawda - pozycja 17
Znaleziono: prawda - pozycja 20
Znaleziono: fałsz
Znaleziono: fałsz
Dopasowanie: fałsz
-----------
Znaleziono: prawda - pozycja 0
Znaleziono: fałsz
Znaleziono: fałsz
Dopasowanie: prawda
Dopasowanie: prawda
Dopasowanie: prawda
Dopasowanie: prawda

Dlatego należy zachować ostrożność podczas find()wielokrotnego wywoływania, jeśli Matcherobiekt nie został zresetowany, nawet jeśli wyrażenie regularne jest otoczone ciągiem znaków ^i $dopasowuje pełny ciąg.

L. Holanda
źródło
2
bardzo pomocny kolega
DockYard
6

find()rozważy podłańcuch względem wyrażenia regularnego, gdzie matches()rozważa wyrażenie pełne.

find() zwraca true tylko, jeśli podłańcuch wyrażenia pasuje do wzorca.

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
        }
    }
Sumanth Varada
źródło
3

matches();nie buforuje, ale find()buforuje. find()najpierw szuka końca łańcucha, indeksuje wynik i zwraca wartość logiczną i odpowiedni indeks.

Właśnie dlatego, gdy masz taki kod

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

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

3:int count = 0;

4:while(matcher.find()){

5:count++: }

O 4: Mechanizm wyrażeń regularnych wykorzystujący strukturę wzorca odczyta cały kod (indeks do indeksu określony przez, regex[single character]aby znaleźć co najmniej jedno dopasowanie. Jeśli takie dopasowanie zostanie znalezione, zostanie zindeksowane, a następnie pętla zostanie wykonana na podstawie zindeksowany wynik, jeśli matches()nie wykonałby wcześniej obliczenia takiego, który nie; Instrukcja while nigdy nie wykonałaby się, ponieważ pierwszym znakiem dopasowanego łańcucha nie jest alfabet.


źródło