countwords.py - Anzahl aller Wörter in einem Text ermitteln

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
TheChairman
User
Beiträge: 1
Registriert: Montag 22. Oktober 2012, 21:05

Ich habe ein kleines Programm geschrieben, dass ermittelt, welche Wörter wie oft in einem Text vorkommen:

Code: Alles auswählen

# -*- coding: cp1252 -*-

def count_words(text):
    """gibt aus, wie oft jedes Wort im String 'text' vorkommt"""
    for i in ["'", ",", ".", ";", ":", "?", "!", "(", ")"]:
        text = text.lower().replace(i, "")
    text = text.replace("\n", " ")
    words = text.split(" ")
    while True:
        if "" in words: words.remove("")
        else: break
    result = []
    counted_words = []
    for i in words:
        if not i in counted_words:
            result.append(i+" : "+str(words.count(i)))
            counted_words.append(i)
    return "\n".join(result)

Code: Alles auswählen

print(count_words("""Fischers Fritz fischt frische Fische, frische Fische fischt Fischers Fritz.
eins; zwei, zwei; drei, drei, drei."""))
>>> 
fischers : 2
fritz : 2
fischt : 2
frische : 2
fische : 2
eins : 1
zwei : 2
drei : 3
Verbesserungsvorschläge/Kritik ist gern gesehen.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Tja, man könnte es kürzer machen:

Code: Alles auswählen

import re
from collections import Counter

text = """Fischers Fritz fischt frische Fische, frische Fische fischt Fritz.
eins; zwei, zwei; drei, drei, drei."""

c = Counter(word.group() for word in re.finditer(r'\w+', text))

print(c)
>>> Counter({'drei': 3, 'fischt': 2, 'frische': 2, 'zwei': 2, 'Fritz': 2, 'Fische': 2, 'Fischers': 2, 'eins': 1})
Ok, man muss es noch hübsch in eine Funktion packen und die Ausgabe anpassen, aber der Ansatz mittels ``collection.Counter`` ist sicher elegant :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@TheChairman: Statt der Liste mit Zeichenketten der Länge 1 hätte man auch eine Zeichenkette mit den zu ersetzenden Zeichen hinschreiben können.

`i` ist ein schlechter Name für alles was keine ganze Zahl ist. Vor allem als Schleifenvariable. Das ist einfach *der* Name für numerische Schleifen-/Zählvariablen.

In jedem Schleifendurchlauf wird der Text in Kleinbuchstaben umgewandelt — das ist spätestens nach dem ersten mal eine unnötige Operation und sollte vor oder hinter die Schleife verschoben werden.

Bei einem einfachen `split()` *ohne* Argumente kann man sich sowohl das ersetzen des Zeilenumbruchs als auch das filtern von leeren Zeichenketten sparen. Letzteres ist sehr ineffizient umgesetzt — da würde man eher eine neue Liste ohne die unerwünschten Elemente erstellen und bräuchte damit nur einmal duch die Elemente gehen. Hier bietet sich eine „list comprehension” an.

Nach einem ``:`` der einen Block einleitet, sollte aus Gründen der übersichtlichkeit ein Zeilenumbruch gesetzt werden. Auch wenn der Block nur eine Zeile enthält.

Der letzte Teil ist wieder furchtbar ineffizient gelöst. Da bietet sich als Datenstruktur ein Wörterbuch an (`dict`), oder ein `collections.defaultdict`, oder gleich ein `collections.Counter`.

Zeichenketten und Werte mit ``+`` und `str()` zusammen zu setzen ist eher BASIC als Python. In Python gibt es dafür den ``%``-Operator oder die `format()`-Methode auf Zeichenketten.

Man könnte das Ergebnis noch sortieren.

Und das mit den Sonderzeichen/Worten ist nicht besonders robust. Ziffern werden zum Beispiel als Worte erkannt. Wenn von einem Basketballspiel die Rede von einem Ergebnis von '42:23' ist, wird das ”Wort” '4223' gezählt. Aus URLs werden die Punkte entfernt…
Antworten