Comment puis-je compter le nombre de correspondances pour une regex?

97

Disons que j'ai une chaîne qui contient ceci:

HelloxxxHelloxxxHello

Je compile un modèle pour rechercher «Bonjour»

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

Il devrait trouver trois correspondances. Comment puis-je compter le nombre de correspondances?

J'ai essayé différentes boucles et utilisé le matcher.groupCount()mais cela n'a pas fonctionné.

Tony
la source
Y a-t-il une chance que votre chaîne de recherche ait des occurrences qui se chevauchent dans la chaîne d'entrée?
aioobe

Réponses:

177

matcher.find()ne trouve pas toutes les correspondances, seulement la correspondance suivante .

Solution pour Java 9+

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

Solution pour Java 8 et versions antérieures

Vous devrez faire ce qui suit. ( À partir de Java 9, il existe une meilleure solution )

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

Btw, matcher.groupCount()c'est quelque chose de complètement différent.

Exemple complet :

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

Gestion des correspondances qui se chevauchent

Lors du comptage des matches de aadans aaaal'extrait ci - dessus vous donnera 2 .

aaaa
aa
  aa

Pour obtenir 3 correspondances, c'est-à-dire ce comportement:

aaaa
aa
 aa
  aa

Vous devez rechercher une correspondance à l'index <start of last match> + 1comme suit:

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
la source
Comptage du nombre de correspondances qui se produisent dans la chaîne. La méthode java.util.regex.Matcher.region (int start, int end) définit les limites de la région de ce matcher. La région est la partie de la séquence d'entrée qui sera recherchée pour trouver une correspondance. L'appel de cette méthode réinitialise le matcher, puis définit la région pour qu'elle commence à l'index spécifié par le paramètre start et se termine à l'index spécifié par le paramètre end. Essaye ça. while(matcher.find()){ matcher.region(matcher.end()-1, str.length()); count++; }
Mukesh Kumar Gupta
17

Cela devrait fonctionner pour les correspondances qui pourraient se chevaucher:

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
la source
5

Depuis Java 9, vous pouvez utiliser le flux fourni par Matcher.results()

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

Si vous souhaitez utiliser les flux Java 8 et êtes allergique aux whileboucles, vous pouvez essayer ceci:

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

Avertissement: cela ne fonctionne que pour les matchs disjoints.

Exemple:

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

Cela imprime:

2
0
1
0

Voici une solution pour les correspondances disjointes avec les flux:

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
la source
1

Utilisez le code ci-dessous pour trouver le nombre de correspondances que l'expression régulière trouve dans votre entrée

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

Il s'agit d'un code généralisé et non spécifique, adaptez-le à vos besoins

N'hésitez pas à me corriger s'il y a une erreur.

dit amir
la source