Wie einen Wortzähler programmieren?

9 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Die einfachste (und bisher schon mehrfach genannte) Methode wäre es, den String anhand von Leerzeichen aufzuspalten.

Aber es gibt da ein paar kleine Problempotentiale:

  1. Wenn mehrere Leerzeichen hintereinanderstehen, dann bekommst du eine falsche Wortzahl.
  2. Nehmen wir den Satz "Peter kauft 400 Wassermelonen.". Ist "400" ein Wort oder nicht? (Definitionssache)
  3. Abkürzungen: "z.B." würde als ein Wort betrachtet werden, "z. B." als zwei.
  4. "400kg" vs. "400 kg": ein Wort oder zwei (und ist "400" überhaupt ein Wort? Siehe 2.)?

Das aufspalten an Leerzeichen ist schonmal ein Anfang, aber ohne "Nachbehandlung" nicht wirklich sinnvoll.

regex9  23.05.2019, 14:23

Lösung für Punkt 1:

array_filter(explode(" ", $text));
2
KarlRanseierIII  23.05.2019, 22:51
@regex9

preg_split() ist für die meisten Problemfälle Dein natürlicher Freund :-D.

2

Die meisten PHP sind leider totale Pfuscher und kennen ihre eigene Programmiersprache kaum, was du an den bisherigen - durchweg schlechten - Antworten auch sehr gut sehen kannst. (Wie üblich mit Ausnahme von regex9 und Isendrak, deren Hinweise du beachten solltest!)

Was dir hier vorgeschlagen wurde, also den String zu splitten und die Anzahl der Elemente im Ergebnis zu zählen, ist wieder mal so eine typisch naive PHP-Entwickler-Lösung, weil es ja offensichtlich keinen langsameren und speicherfressenderen Weg gibt.

Aber egal, ein vernünftiger Programmierer würde das so machen:

function wortzaehler($s) {
  return str_word_count($s);
}

$s = "abc def ghi";
$w = wortzaehler($s);

file_put_contents('wortanzahl.txt', $w, LOCK_EX);

Ja, richtig gesehen! PHP hat dafür bereits eine fertige Funktion. Gut, diese Funktion existiert zwar erst seit 15 Jahren, aber du kannst nicht davon ausgehen, dass der gemeine PHP-Entwickler schon mal etwas davon gehört hat ... also das gleiche wie bei 90% aller PHP-Funktionen, denn sich mal systematisch durch die Dokumentation zu arbeiten ist für einen PHPler natürlich zu viel verlangt. Aber egal ...

Da es Teil deiner Aufgabe ist, das Ergebnis in eine Datei zu schreiben, solltest du die file_put_contents()-Funktion nutzen, die einfach nur ein Argument in eine Datei schreibt. Ich habe dabei den optionalen Parameter LOCK_EX genutzt, den durchschnittliche PHP-Programmierer normalerweise nie nutzen und meistens auch nicht mal kennen, aber er sorgt dafür, dass es in deiner Datei nicht zu Datensalat kommt, falls mehrere Leute parallel in die Datei schreiben sollten. (File locking ist bei so ziemlich allen anderen Programmiersprachen Usus, aber in der PHP-Welt irgendwie noch nicht so richtig angekommen ... und deshalb hat die Schwesterfunktion file_get_contents() auch überhaupt kein Argument fürs Locking, aber etwas anderes erwartet man bei PHP natürlich auch nicht. Ein konsistentes API-Design? Vergiss es!)

Es gibt natürlich noch mehr Möglichkeiten, deine wortzaehler()-Funktion zu implementieren, aber nehmen wir einfach nur mal zwei naheliegende Varianten:

function wortzaehler($s) {
  return count_chars($s)[ord(' ')] + 1;
}

Damit wird einfach die Anzahl aller Zeichen im String gezählt, und die Anzahl der Lehrzeichen um eins erhöht. Das ist zwar nicht allzu performant, da leider ALLE Zeichen gezählt werden, aber immer noch eleganter als mit explode() herum zu pfuschen.

Dann gibt es noch die Möglichkeit mit sog. regulären Ausdrücken, Stringfunktionen wie strstr() oder auch das händische Zählen in einer Schleife.

Leider ist PHP vom Sprachdesign her so verkorkst, dass eine schicke foreach-Schleife oder die gängigen Array-Funktionen nicht generisch mit Strings funktionieren, sodass du auf eine herkömmliche Schleife angewiesen bist:

function wortzaehler($s) {
  $spaces = 0;

  for ($i = 0, $len = strlen($s); $i < $len; ++$i) {
    if ($s[$i] === ' ') {
      ++$spaces;
    }
  }

  return $spaces + 1;
}

Vermutlich erwartet dein Lehrer eine Lösung in dieser Art, du kannst aber nur selbst entscheiden, welche Herangehensweise du bevorzugst. (Im Übrigen würde ich an deiner Stelle immer englischsprachige Bezeichner wählen, aber da dein Lehrer ja eine "wortzaehler" Funktion haben will, die auch so heißt, hab ich das mal in den obigen Code-Schnipseln so übernommen.)

Fazit: PHP ist eine recht wirre und inkonsistente Sprache (verglichen mit anderen), deren Entwickler meistens - mehr noch als in allen anderen Sprachen - ziemliche Dilettanten sind. Gute, defensive und performante Programmierung suchst du unter PHPlern oft vergebens.

Falls du die Möglichkeit hast, lerne lieber eine andere ordentliche Programmiersprache, wobei eigentlich völlig egal ist welche, da es nirgends so schlimm ist, wie bei PHP.

Trotzdem viel Erfolg mit deinen Hausaufgaben und lass dich von der laienhaften Umgebung in der PHP-Welt nicht entmutigen! Woanders ist es nicht so schlimm! ;)

Woher ich das weiß:Berufserfahrung
KarlRanseierIII  24.05.2019, 03:24

Ich muß gestehen ich las str_word_count() und fragte mich, wieso mir die Funktion nicht im Bewußtsein war. Dann habe ich kurz in die Referenz geschaut und las:

Beachten Sie bei der Verwendung dieser Funktion, dass "Wörter" als locale-abhängige Strings interpretiert werden, die nur die Buchstaben des Alphabets enthalten. Sie dürfen außerdem "'"- und "-"-Zeichen enthalten, jedoch nicht damit beginnen.

Und da fangen dann leider die Probleme an, denn die Locale muß zum Text passen:

php -r 'print_r(str_word_count("Häschen ist müde",1));'
Array
(
    [0] => H
    [1] => schen
    [2] => ist
    [3] => m
    [4] => de
)

Klappt nicht so wirklich toll ;-). PCRE ist dabei auch nicht deutlich besser, da kann es einen auch ruckzuck auf die Nase legen... Aber das nur am Rande.

2
sqrt214142  24.05.2019, 15:05
@KarlRanseierIII

Genau! Wörter zuverlässig zählen hat viel mehr Fallstricke, als man erwarten würde. Übrigens, verdammt niedlicher Beispielsatz! ;)

0
KarlRanseierIII  24.05.2019, 21:06
@sqrt214142

Die Frage ist nur:

Wie die korrekte Locale bestimmen? Und was bei Multilocale-Texten, von Multialphabet will ich gar nicht erst anfangen - Da kannste solche Funktionen per se in die Tonne werfen. Aber es ist ja noch ein wenig lustiger:

 php -r 'echo setlocale(LC_ALL,0)."\n";'
LC_CTYPE=en_US.utf8;LC_NUMERIC=C;LC_TIME=C;LC_COLLATE=C;LC_MONETARY=C;LC_MESSAGES=C;LC_PAPER=C;LC_NAME=C;LC_ADDRESS=C;LC_TELEPHONE=C;LC_MEASUREMENT=C;LC_IDENTIFICATION=C

Warum alle LCs auf C stehen weiß nur php, denn:

locale
LANG=en_US.utf8
LC_CTYPE="en_US.utf8"
LC_NUMERIC="en_US.utf8"
LC_TIME="en_US.utf8"
LC_COLLATE="en_US.utf8"
LC_MONETARY="en_US.utf8"
LC_MESSAGES="en_US.utf8"
LC_PAPER="en_US.utf8"
LC_NAME="en_US.utf8"
LC_ADDRESS="en_US.utf8"
LC_TELEPHONE="en_US.utf8"
LC_MEASUREMENT="en_US.utf8"
LC_IDENTIFICATION="en_US.utf8"

Hmm, schaun mer mal:

LC_ALL="de_DE.UTF8" php -r 'echo setlocale(LC_ALL,0)."\n";'
LC_CTYPE=de_DE.UTF8;LC_NUMERIC=C;LC_TIME=C;LC_COLLATE=C;LC_MONETARY=C;LC_MESSAGES=C;LC_PAPER=C;LC_NAME=C;LC_ADDRESS=C;LC_TELEPHONE=C;LC_MEASUREMENT=C;LC_IDENTIFICATION=C

WTF? eigentlich müßte LC_ALL und somit LC_* gesetzt werden, siehe nächste Variante.

Mit LANG geht es übrigens genausowenig.

php -r 'echo setlocale(LC_ALL,"de_DE.utf8")."\n";echo setlocale(LC_ALL,0)."\n";print_r(str_word_count("Häschen ist müde",2));'
de_DE.utf8
de_DE.utf8
Array
(
    [0] => H
    [3] => schen
    [9] => ist
    [13] => m
    [16] => de
)

Immer noch nicht ... ich lese mir jetzt nicht den Source von PHP durch, aber so sollte es nicht sein :-). Aber alleine schon, daß die Systemlocale nicht korrekt übernommen wird, lässt micht ein wenig den Kopf schütteln ...

1
sqrt214142  24.05.2019, 23:47
@KarlRanseierIII

Ist eben PHP. Was willste da schon erwarten! ;)

Viele PHP-Funktionen, die laut Dokumentation auf php.net im Fehlerfall "FALSE" zurück geben können sollen, sind in Wirklichkeit so implementiert, dass es unmöglilch ist, diesen Wert jemals zu erhalten. Stattdessen werden mögliche Fehler verschluckt.

Aber so etwas sieht man leider nur, wenn man sich die Quellen vom PHP-Interpreter anguckt. :)

1
KarlRanseierIII  25.05.2019, 00:05
@sqrt214142

Da ist etwas dran, die Diskussionen mit PHP-Devs sind äußerst 'fruchtbar' ... äääh .. moment, ich meinte glaube ich furchtbar :-D.

1

Die Frage ist natürlich was der Zweck der Übung sein soll, ob Du also als Übung einen Tokenizer schreiben sollst, um so die Wörter zu zählen, oder ob Du Möglichkeiten finden sollst, die Dir PHP bietet.

jeder buchstabe an dem hinten ein leerzeichen drangehängt ist ist ein wort außer beim letzten wort da ist es vorne ein ding dran

verreisterNutzer  23.05.2019, 13:50

.... und was mach ich mit dem "ding"??

0
Bardegerder  23.05.2019, 14:52
@verreisterNutzer

ja du hast ein iq von unter 100 weil man braucht über 100 um logische schlussfolgerungen aus dumen mesnchen zu sehen

0

Nutze doch die explode() Funktion in PHP

https://www.w3schools.com/php/func_string_explode.asp

Als Trennzeichen nimmst du das Leerzeichen wie im Beispiel zu sehen.

Die explode Funktion setzt du natürlich in eine Variable, diese Variable enthält jetzt ein Array aller Wörter - das Array kannst du dann mit count zählen.

Woher ich das weiß:Berufserfahrung – Software-Entwickler