Come posso contare il numero di corrispondenze per una regex?


97

Diciamo che ho una stringa che contiene questo:

HelloxxxHelloxxxHello

Compilo uno schema per cercare "Hello"

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

Dovrebbe trovare tre corrispondenze. Come posso contare quante partite c'erano?

Ho provato vari loop e usando il matcher.groupCount()ma non ha funzionato.


C'è qualche possibilità che la tua stringa di ricerca possa avere occorrenze sovrapposte nella stringa di input?
aioobe

Risposte:


177

matcher.find()non trova tutte le corrispondenze, solo quella successiva .

Soluzione per Java 9+

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

Soluzione per Java 8 e versioni precedenti

Dovrai fare quanto segue. ( A partire da Java 9, c'è una soluzione migliore )

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

A proposito, matcher.groupCount()è qualcosa di completamente diverso.

Esempio completo :

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
    }
}

Gestione di partite sovrapposte

Quando si contano le corrispondenze di aanello aaaasnippet sopra, si ottengono 2 .

aaaa
aa
  aa

Per ottenere 3 corrispondenze, ovvero questo comportamento:

aaaa
aa
 aa
  aa

Devi cercare una corrispondenza all'indice <start of last match> + 1come segue:

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

Conteggio del numero di corrispondenze che si verificano all'interno della stringa. Il metodo java.util.regex.Matcher.region (int start, int end) imposta i limiti della regione di questo matcher. La regione è la parte della sequenza di input che verrà cercata per trovare una corrispondenza. L'invocazione di questo metodo reimposta il matcher, quindi imposta la regione in modo che inizi in corrispondenza dell'indice specificato dal parametro start e termini in corrispondenza dell'indice specificato dal parametro end. Prova questo. while(matcher.find()){ matcher.region(matcher.end()-1, str.length()); count++; }
Mukesh Kumar Gupta

17

Questo dovrebbe funzionare per le partite che potrebbero sovrapporsi:

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

Se desideri utilizzare flussi Java 8 e sei allergico ai whileloop, puoi provare questo:

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

Disclaimer: funziona solo per le partite disgiunte.

Esempio:

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

Questo stampa:

2
0
1
0

Questa è una soluzione per partite disgiunte con flussi:

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

Usa il codice seguente per trovare il conteggio del numero di corrispondenze che la regex trova nel tuo input

        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++;

Questo è un codice generalizzato non specifico, adattalo alle tue esigenze

Non esitate a correggermi in caso di errore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.