Jak mogę policzyć liczbę dopasowań dla wyrażenia regularnego?


99

Powiedzmy, że mam ciąg, który zawiera to:

HelloxxxHelloxxxHello

Kompiluję wzorzec w celu wyszukania hasła „Hello”

Pattern pattern = Pattern.compile("Hello");
Matcher matcher = pattern.matcher("HelloxxxHelloxxxHello");

Powinien znaleźć trzy dopasowania. Jak mogę policzyć, ile było meczów?

Próbowałem różnych pętli i używania, matcher.groupCount()ale to nie zadziałało.


Czy jest jakaś szansa, że ​​Twój ciąg wyszukiwania może mieć nakładające się wystąpienia w ciągu wejściowym?
aioobe

Odpowiedzi:


178

matcher.find()nie znajduje wszystkich dopasowań, tylko następne dopasowanie.

Rozwiązanie dla Java 9+

long matches = matcher.results().count();

Rozwiązanie dla Java 8 i starszych

Będziesz musiał wykonać następujące czynności. ( Począwszy od Java 9, istnieje ładniejsze rozwiązanie )

int count = 0;
while (matcher.find())
    count++;

Przy okazji, matcher.groupCount()to coś zupełnie innego.

Kompletny przykład :

import java.util.regex.*;

class Test {
    public static void main(String[] args) {
        String hello = "HelloxxxHelloxxxHello";
        Pattern pattern = Pattern.compile("Hello");
        Matcher matcher = pattern.matcher(hello);

        int count = 0;
        while (matcher.find())
            count++;

        System.out.println(count);    // prints 3
    }
}

Obsługa pokrywających się dopasowań

Liczenie dopasowań aaw aaaapowyższym fragmencie daje 2 .

aaaa
aa
  aa

Aby uzyskać 3 dopasowania, czyli takie zachowanie:

aaaa
aa
 aa
  aa

Musisz szukać dopasowania w indeksie <start of last match> + 1w następujący sposób:

String hello = "aaaa";
Pattern pattern = Pattern.compile("aa");
Matcher matcher = pattern.matcher(hello);

int count = 0;
int i = 0;
while (matcher.find(i)) {
    count++;
    i = matcher.start() + 1;
}

System.out.println(count);    // prints 3

Zliczanie liczby dopasowań, które występują w ciągu. Metoda java.util.regex.Matcher.region (int start, int end) określa granice regionu tego dopasowania. Region jest częścią sekwencji wejściowej, która będzie przeszukiwana w celu znalezienia dopasowania. Wywołanie tej metody resetuje dopasowanie, a następnie ustawia region tak, aby zaczynał się od indeksu określonego przez parametr start i kończył się indeksem określonym przez parametr end. Spróbuj tego. while(matcher.find()){ matcher.region(matcher.end()-1, str.length()); count++; }
Mukesh Kumar Gupta

17

To powinno działać w przypadku dopasowań, które mogą się nakładać:

public static void main(String[] args) {
    String input = "aaaaaaaa";
    String regex = "aa";
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(input);
    int from = 0;
    int count = 0;
    while(matcher.find(from)) {
        count++;
        from = matcher.start() + 1;
    }
    System.out.println(count);
}


3

Jeśli chcesz używać strumieni Java 8 i jesteś uczulony na whilepętle, możesz spróbować tego:

public static int countPattern(String references, Pattern referencePattern) {
    Matcher matcher = referencePattern.matcher(references);
    return Stream.iterate(0, i -> i + 1)
            .filter(i -> !matcher.find())
            .findFirst()
            .get();
}

Zastrzeżenie: działa to tylko w przypadku rozłącznych meczów.

Przykład:

public static void main(String[] args) throws ParseException {
    Pattern referencePattern = Pattern.compile("PASSENGER:\\d+");
    System.out.println(countPattern("[ \"PASSENGER:1\", \"PASSENGER:2\", \"AIR:1\", \"AIR:2\", \"FOP:2\" ]", referencePattern));
    System.out.println(countPattern("[ \"AIR:1\", \"AIR:2\", \"FOP:2\" ]", referencePattern));
    System.out.println(countPattern("[ \"AIR:1\", \"AIR:2\", \"FOP:2\", \"PASSENGER:1\" ]", referencePattern));
    System.out.println(countPattern("[  ]", referencePattern));
}

To drukuje:

2
0
1
0

To jest rozwiązanie dla rozłącznych meczów ze strumieniami:

public static int countPattern(String references, Pattern referencePattern) {
    return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
            new Iterator<Integer>() {
                Matcher matcher = referencePattern.matcher(references);
                int from = 0;

                @Override
                public boolean hasNext() {
                    return matcher.find(from);
                }

                @Override
                public Integer next() {
                    from = matcher.start() + 1;
                    return 1;
                }
            },
            Spliterator.IMMUTABLE), false).reduce(0, (a, c) -> a + c);
}

1

Użyj poniższego kodu, aby znaleźć liczbę dopasowań znalezionych przez wyrażenie regularne w danych wejściowych

        Pattern p = Pattern.compile(regex, Pattern.MULTILINE | Pattern.DOTALL);// "regex" here indicates your predefined regex.
        Matcher m = p.matcher(pattern); // "pattern" indicates your string to match the pattern against with
        boolean b = m.matches();
        if(b)
        count++;
        while (m.find())
        count++;

Jest to jednak kod uogólniony, a nie konkretny, dostosuj go do swoich potrzeb

Prosimy o poprawienie mnie, jeśli jest jakiś błąd.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.