¿Cómo puedo contar el número de coincidencias para una expresión regular?

97

Digamos que tengo una cadena que contiene esto:

HelloxxxHelloxxxHello

Recopilo un patrón para buscar 'Hola'

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

Debería encontrar tres coincidencias. ¿Cómo puedo contar cuántas coincidencias hubo?

Probé varios bucles y usé el matcher.groupCount()pero no funcionó.

Tony
fuente
¿Existe alguna posibilidad de que su cadena de búsqueda tenga ocurrencias superpuestas en la cadena de entrada?
aioobe

Respuestas:

177

matcher.find()no encuentra todas las coincidencias, solo la siguiente .

Solución para Java 9+

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

Solución para Java 8 y versiones anteriores

Tendrá que hacer lo siguiente. ( A partir de Java 9, hay una mejor solución )

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

Por cierto, matcher.groupCount()es algo completamente diferente.

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

Manejo de coincidencias superpuestas

Al contar las coincidencias de aaen aaaael fragmento anterior, obtendrá 2 .

aaaa
aa
  aa

Para obtener 3 coincidencias, es decir, este comportamiento:

aaaa
aa
 aa
  aa

Debe buscar una coincidencia en el índice de la <start of last match> + 1siguiente manera:

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
aioobe
fuente
Contando el número de coincidencias que ocurren dentro de la cadena. El método java.util.regex.Matcher.region (int start, int end) establece los límites de la región de este comparador. La región es la parte de la secuencia de entrada que se buscará para encontrar una coincidencia. La invocación de este método restablece el comparador y luego establece la región para que comience en el índice especificado por el parámetro de inicio y finalice en el índice especificado por el parámetro de fin. Prueba esto. while(matcher.find()){ matcher.region(matcher.end()-1, str.length()); count++; }
Mukesh Kumar Gupta
17

Esto debería funcionar para coincidencias que podrían superponerse:

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);
}
Mary-Anne Wolf
fuente
5

Desde Java 9, puede utilizar la secuencia proporcionada por Matcher.results()

long matches = matcher.results().count();
vương trọng hồ
fuente
3

Si desea utilizar secuencias de Java 8 y es alérgico a los whilebucles, puede probar esto:

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

Descargo de responsabilidad: esto solo funciona para coincidencias disjuntas.

Ejemplo:

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

Esto imprime:

2
0
1
0

Esta es una solución para coincidencias disjuntas con transmisiones:

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);
}
gil.fernandes
fuente
1

Use el siguiente código para encontrar el número de coincidencias que la expresión regular encuentra en su entrada

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

Sin embargo, este es un código generalizado, no específico, adáptelo a sus necesidades

No dude en corregirme si hay algún error.

sayed amir
fuente