Comment compter les mots dans une chaîne en Java
Comptez les mots d'une chaîne Java avec trim et split sur les espaces, un matcher regex, en évitant le split naïf sur un seul espace.
Compter les mots d'une chaîne semble trivial — diviser sur les espaces et compter les parties — mais la version naïve échoue dès que l'entrée contient des espaces en début, en fin ou répétés. Ce chapitre présente les manières idiomatiques de compter les mots en Java, les cas limites qui piègent les développeurs, et quelle approche privilégier. Il s'appuie sur les bases abordées dans Java Strings et String split and join.
Diviser sur les espaces blancs (la valeur par défaut fiable)
La recette standard consiste à supprimer les espaces en début et fin de chaîne, puis à la diviser sur un ou plusieurs caractères d'espacement avec l'expression régulière \s+ :
String text = " The quick brown fox ";
String trimmed = text.trim();
int words = trimmed.isEmpty() ? 0 : trimmed.split("\\s+").length;
System.out.println(words); // 4Deux détails rendent cela correct. Le trim() supprime les espaces de début et de fin, car split("\\s+") appliqué à une chaîne qui commence par des espaces produit un élément vide en tête. La garde isEmpty() gère les entrées vides : diviser "" renvoie un tableau de longueur 1, et non 0, donc sans cette vérification une chaîne vide signalerait à tort un mot.
\\s est un littéral de chaîne Java pour l'expression régulière \s, qui correspond aux espaces, tabulations et sauts de ligne. Le + signifie « un ou plusieurs », de sorte que toute séquence d'espaces est comptée comme un seul séparateur.
Éviter le split naïf sur un seul espace
Il est tentant d'écrire text.split(" ").length, mais cela divise sur exactement un espace et échoue sur des entrées réelles :
String text = " The quick brown fox ";
System.out.println(text.split(" ").length); // 8, not 4Les deux espaces en début produisent deux éléments vides en tête, et chaque séquence de trois espaces internes en ajoute davantage — le tableau est donc ["", "", "The", "quick", "", "", "brown", "fox"], huit éléments au lieu de quatre. (Le split de Java supprime les chaînes vides de fin, c'est pourquoi les deux espaces finaux n'ajoutent rien.) Chaque espace doublé et chaque espace en début gonfle le comptage. Diviser sur " " n'est sûr que si l'on sait déjà que l'entrée est une ligne délimitée par un seul espace sans espacement supplémentaire — ce qui est rarement garanti.
Compter les tokens avec un matcher regex
Au lieu de diviser, on peut rechercher directement les tokens de mots et compter les correspondances. Cela contourne entièrement le problème des éléments vides :
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Matcher m = Pattern.compile("\\w+").matcher(text);
int count = 0;
while (m.find()) {
count++;
}\w+ correspond à des séquences de caractères de mot (lettres, chiffres, underscore). Parce qu'il recherche des mots plutôt que des séparateurs, les espaces en début, en fin et répétés sont sans importance — aucune garde n'est nécessaire. La contrepartie est que \w exclut la ponctuation, donc un "well-known" avec trait d'union compte comme deux tokens. Choisissez le motif en fonction de votre définition d'un « mot ».
Si vous devez tokeniser un document plus long ou un flux plutôt qu'une seule ligne, le chapitre Java StringTokenizer couvre une classe spécialement conçue pour découper du texte en tokens.
| Approche | Gère les espaces supplémentaires/limites | Sûre avec chaîne vide | Remarque |
|---|---|---|---|
split(" ") | Non | Non | Échoue sur les espaces répétés |
trim().split("\\s+") | Oui | Avec la garde isEmpty() | La valeur par défaut recommandée |
Matcher Pattern \w+ | Oui | Oui (compte 0) | Divise sur la ponctuation |
Un exemple complet
Ce que l'on retient de l'exécution :
Naive split length: 8prouve quesplit(" ")surestime le compte car chaque espace de début et chaque espace à l'intérieur d'une séquence produit un élément tableau vide supplémentaire.Whitespace split: 4montre quetrim().split("\\s+")regroupe toute séquence d'espaces et donne le bon compte.Regex matcher: 4confirme que le matcher\w+aboutit au même résultat sans aucun découpage préalable ni garde.Blank input words: 0démontre pourquoi la gardeisEmpty()est importante — sans elle, une entrée vide signalerait à tort un mot.- Les trois méthodes correctes s'accordent sur
4, donc la différence entre elles tient à la robustesse et à la définition d'un « mot », pas au résultat sur une entrée propre.