Wörter in einem String in Java zählen
Wörter in einem Java-String korrekt zählen mit trim und split auf Leerzeichen, einem Regex-Matcher und ohne den naiven Einzel-Leerzeichen-Split.
Wörter in einem String zu zählen klingt trivial — auf Leerzeichen aufteilen und die Teile zählen — aber die naive Version bricht in dem Moment, in dem die Eingabe führende, nachfolgende oder wiederholte Leerzeichen enthält. Dieses Kapitel zeigt die idiomatischen Wege zum Zählen von Wörtern in Java, die Randfälle, über die man stolpert, und welchen Ansatz man wählen sollte. Es baut auf den Grundlagen in Java Strings und String split and join auf.
Auf Leerzeichen aufteilen (die zuverlässige Standardmethode)
Das Standardrezept besteht darin, den String zu trimmen und ihn dann mit dem Regex \s+ auf ein oder mehr Leerzeichen aufzuteilen:
String text = " The quick brown fox ";
String trimmed = text.trim();
int words = trimmed.isEmpty() ? 0 : trimmed.split("\\s+").length;
System.out.println(words); // 4Zwei Details machen dies korrekt. trim() entfernt die führenden und nachfolgenden Leerzeichen, da split("\\s+") auf einem String, der mit Leerzeichen beginnt, ein leeres führendes Element erzeugt. Der isEmpty()-Guard behandelt leere Eingaben: Das Aufteilen von "" liefert ein Array der Länge 1, nicht 0, sodass ohne die Prüfung ein leerer String fälschlicherweise ein Wort melden würde.
Das \\s ist ein Java-String-Literal für den Regex \s, der Leerzeichen, Tabs und Zeilenumbrüche trifft. Das + bedeutet „ein oder mehr", sodass jede Folge von Leerzeichen als ein einziges Trennzeichen gilt.
Den naiven Einzel-Leerzeichen-Split vermeiden
Es ist verlockend, text.split(" ").length zu schreiben, aber das teilt auf genau einem Leerzeichen auf und bricht bei realen Eingaben:
String text = " The quick brown fox ";
System.out.println(text.split(" ").length); // 8, not 4Die zwei führenden Leerzeichen erzeugen zwei leere führende Elemente, und jede Folge von drei internen Leerzeichen fügt mehr hinzu — das Array ist also ["", "", "The", "quick", "", "", "brown", "fox"], acht Elemente statt vier. (Javas split verwirft nachfolgende leere Strings, weshalb die zwei abschließenden Leerzeichen nichts hinzufügen.) Jedes doppelte Leerzeichen und jedes führende Leerzeichen bläht die Zählung auf. Das Aufteilen auf " " ist nur sicher, wenn man bereits weiß, dass die Eingabe eine einzelne leerzeichengetrennte Zeile ohne zusätzliche Abstände ist — was selten garantiert ist.
Token mit einem Regex-Matcher zählen
Anstatt aufzuteilen, kann man Wort-Token direkt treffen und die Treffer zählen. Dies umgeht das Leer-Element-Problem vollständig:
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+ trifft Folgen von Wortzeichen (Buchstaben, Ziffern, Unterstrich). Da es nach Wörtern sucht und nicht nach Trennzeichen, sind führende, nachfolgende und wiederholte Leerzeichen irrelevant — kein Guard erforderlich. Der Kompromiss ist, dass \w Interpunktion ausschließt, sodass ein getrenntes "well-known" als zwei Token gilt. Wählen Sie das Muster passend zu Ihrer Definition von „Wort".
Wenn Sie ein längeres Dokument oder einen Stream statt einer einzelnen Zeile tokenisieren müssen, behandelt das Kapitel Java StringTokenizer eine Klasse, die speziell zum Aufteilen von Text in Token entwickelt wurde.
| Ansatz | Behandelt extra/Rand-Leerzeichen | Leer-String-sicher | Hinweis |
|---|---|---|---|
split(" ") | Nein | Nein | Bricht bei wiederholten Leerzeichen |
trim().split("\\s+") | Ja | Mit isEmpty()-Guard | Die Standard-Methode |
Pattern \w+ matcher | Ja | Ja (zählt 0) | Teilt bei Interpunktion |
Ein vollständiges Beispiel
Was aus dem Ergebnis zu entnehmen ist:
Naive split length: 8beweist, dasssplit(" ")stark überzählt, weil jedes führende Leerzeichen und jedes Leerzeichen innerhalb einer Folge ein zusätzliches leeres Array-Element erzeugt.Whitespace split: 4zeigt, dasstrim().split("\\s+")jede Folge von Leerzeichen zusammenfasst und die korrekte Zählung liefert.Regex matcher: 4bestätigt, dass der\w+-Matcher das gleiche Ergebnis ohne Trimmen oder Guards erreicht.Blank input words: 0zeigt, warum derisEmpty()-Guard wichtig ist — ohne ihn würde eine leere Eingabe fälschlicherweise ein Wort melden.- Alle drei korrekten Methoden stimmen auf
4überein, sodass der Unterschied zwischen ihnen Robustheit und Definition von „Wort" ist, nicht das Ergebnis bei sauberer Eingabe.