Java : compter le nombre d'occurrences de mots dans la chaîne

Introduction

Compter le nombre d'occurrences de mots dans une chaîne est une tâche assez facile, mais il existe plusieurs approches pour le faire. Vous devez également tenir compte de l'efficacité de la méthode, car vous souhaiterez généralement utiliser des outils automatisés lorsque vous ne souhaitez pas effectuer de travail manuel, c'est-à-dire lorsque l'espace de recherche est grand.

Dans ce guide, vous apprendrez à compter le nombre d'occurrences de mots dans une chaîne en Java :

String searchText = "Your body may be chrome, but the heart never changes. It wants what it wants.";
String targetWord = "wants";

Nous allons rechercher le nombre d'occurrences de targetWord, en utilisant String.split(), Collections.frequency() et Expressions régulières.

Compter les occurrences de mots dans la chaîne avec Chaîne.split()

La façon la plus simple de compter l'occurrence d'un mot cible dans une chaîne est de diviser la chaîne sur chaque mot et de parcourir le tableau, en incrémentant un wordCount sur chaque match. Notez que lorsqu'un mot est entouré d'une ponctuation, telle que wants. à la fin de la phrase - la simple division au niveau du mot traitera correctement wants ainsi que les wants. comme mots séparés !

Pour contourner ce problème, vous pouvez facilement supprimer toute ponctuation de la phrase before le diviser :

String[] words = searchText.replaceAll("p{Punct}", "").split(" ");

int wordCount = 0;
for (int i=0; i < words.length; i++)
    if (words[i].equals(targetWord))
        wordCount++;
System.out.println(wordCount);

Dans le for boucle, nous parcourons simplement le tableau, en vérifiant si l'élément à chaque index est égal au targetWord. Si c'est le cas, nous incrémentons le wordCount, qui à la fin de l'exécution, affiche :

2

Compter les occurrences de mots dans la chaîne avec Collections.fréquence()

Les Collections.frequency() fournit une implémentation beaucoup plus propre et de niveau supérieur, qui fait abstraction d'un simple for boucle et vérifie à la fois l'identité (si un objet is un autre objet) et l'égalité (si un objet est égal à un autre objet, selon les caractéristiques qualitatives de cet objet).

Les frequency() La méthode accepte une liste à parcourir et l'objet cible, et fonctionne également pour tous les autres objets, où le comportement dépend de la façon dont l'objet lui-même implémente equals(). Dans le cas des chaînes, equals() vérifie la contenu de la chaîne:


searchText = searchText.replaceAll("p{Punct}", "");

int wordCount = Collections.frequency(Arrays.asList(searchText.split(" ")), targetWord);
System.out.println(wordCount);

Ici, nous avons converti le tableau obtenu à partir de split() dans un Java ArrayList, à l'aide de l'assistant asList() méthode de Arrays classe. L'opération de réduction frequency() renvoie un entier indiquant la fréquence de targetWord dans la liste, et donne :

2

Occurrences de mots dans une chaîne avec Matcher (expressions régulières – RegEx)

Enfin, vous pouvez utiliser des expressions régulières pour rechercher des modèles et compter le nombre de modèles correspondants. Les expressions régulières sont faites pour cela, c'est donc un choix très naturel pour la tâche. En Java, le Pattern la classe est utilisée pour représenter et compiler des expressions régulières, et la Matcher class est utilisé pour trouver et faire correspondre des modèles.

En utilisant RegEx, nous pouvons coder l'invariance de ponctuation dans l'expression elle-même, il n'est donc pas nécessaire de formater la chaîne en externe ou de supprimer la ponctuation, ce qui est préférable pour les textes volumineux où le stockage d'une autre version modifiée en mémoire peut être coûteux :

Pattern pattern = Pattern.compile("b%s(?!w)".format(targetWord));

Pattern pattern = Pattern.compile("bwants(?!w)");
Matcher matcher = pattern.matcher(searchText);

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

System.out.println(wordCount);

Cela se traduit également par:

2

Référence d'efficacité

Alors, lequel est le plus efficace ? Faisons un petit benchmark :

int runs = 100000;

long start1 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
    int result = countOccurencesWithSplit(searchText, targetWord);
}

long end1 = System.currentTimeMillis();
System.out.println(String.format("Array split approach took: %s miliseconds", end1-start1));

long start2 = System.currentTimeMillis();
  for (int i = 0; i < runs; i++) {
    int result = countOccurencesWithCollections(searchText, targetWord);
}

long end2 = System.currentTimeMillis();
System.out.println(String.format("Collections.frequency() approach took: %s miliseconds", end2-start2));

long start3 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
    int result = countOccurencesWithRegex(searchText, targetWord);
}

long end3 = System.currentTimeMillis();
System.out.println(String.format("Regex approach took: %s miliseconds", end3-start3));

Chaque méthode sera exécutée 100000 XNUMX fois (plus le nombre est élevé, plus la variance et les résultats sont faibles en raison du hasard, en raison de la loi des grands nombres). L'exécution de ce code donne :

Array split approach took: 152 miliseconds
Collections.frequency() approach took: 140 miliseconds
Regex approach took: 92 miliseconds

Cependant, que se passe-t-il si nous rendons la recherche plus coûteuse en termes de calcul en l'agrandissant ? Générons une phrase synthétique :

List possibleWords = Arrays.asList("hello", "world ");
StringBuffer searchTextBuffer = new StringBuffer();

for (int i = 0; i < 100; i++) {
    searchTextBuffer.append(String.join(" ", possibleWords));
}
System.out.println(searchTextBuffer);

Cela crée une chaîne avec le contenu :

hello world hello world hello world hello ...

Consultez notre guide pratique et pratique pour apprendre Git, avec les meilleures pratiques, les normes acceptées par l'industrie et la feuille de triche incluse. Arrêtez de googler les commandes Git et en fait apprendre il!

Maintenant, si nous devions rechercher soit "bonjour" soit "monde" - il y aurait beaucoup plus de correspondances que les deux précédentes. Comment nos méthodes se comportent-elles maintenant dans le benchmark ?

Array split approach took: 606 miliseconds
Collections.frequency() approach took: 899 miliseconds
Regex approach took: 801 miliseconds

Désormais, le fractionnement de tableau est le plus rapide ! En général, les benchmarks dépendent de divers facteurs - tels que l'espace de recherche, le mot cible, etc. et votre cas d'utilisation personnel peut être différent du benchmark.

Conseils: Essayez les méthodes sur votre propre texte, notez les heures et choisissez la plus efficace et la plus élégante pour vous.

Conclusion

Dans ce petit guide, nous avons examiné comment compter les occurrences de mots pour un mot cible, dans une chaîne en Java. Nous avons commencé par diviser la chaîne et en utilisant un simple compteur, puis en utilisant le Collections classe d'assistance, et enfin, en utilisant des expressions régulières.

Au final, nous avons comparé les méthodes et noté que les performances ne sont pas linéaires et dépendent de l'espace de recherche. Pour les textes d'entrée plus longs avec de nombreuses correspondances, la division des tableaux semble être la plus performante. Essayez les trois méthodes par vous-même et choisissez la plus performante.

Horodatage:

Plus de Stackabuse