Wörter mit Python zählen (Teil II)

Gehen wir zurück in das Jahr 2018. Nachdem damals der Koalitionsvertrag verabschiedet wurde, hatte ich ein kleines Skript vorgestellt, mit dem die Häufigkeit eines bestimmten Suchbegriffs ermittelt werden konnte.

Nun gibt es einen neuen Koalitionsvertrag und damit eine Aktualisierung des damaligen Skripts. Der nachfolgend gezeigte Code mag für jene von Interesse sein, die wissen möchten,

  • wie argparse verwendet werden kann,
  • wie Wörter (in einem Dictionary) mit get() gezählt werden können und
  • wie logging implementiert wird.

Voraussetzungen

Diese Version wurde unter Verwendung von Python 3.10 getestet.

Für die Formatierung wird Black verwendet, das mit pip installiert werden kann:

$ pip install black   # Windows
$ pip3 install black # Linux, macOS

Die Formatierung kann anschließend mit der Anweisung

$ black <Dateiname>

durchgeführt werden.

Der Code

Zunächst zeige ich den kompletten Code dieser Version, dann folgen einige Anmerkungen:

import re
import argparse
import logging

# logging.basicConfig(level=logging.disable())  # <- deaktiviert
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger()

VERSION = "1.0"
FILE_NAME = "koalitionsvertrag_2021.txt"  # <- Enter your file here.


def get_parser() -> argparse.ArgumentParser:
    """
    Create a command line parser.
    Returns:
        argparse.ArgumentParser: Created parser
    """
    parser = argparse.ArgumentParser()

    parser.add_argument(
        "-w", 
        "--word", 
        type=str, 
        required=False, 
        help="the word to search for"
    )

    parser.add_argument(
        "-v", 
        "--version", 
        required=False, 
        action="store_true", 
        help="show the version"
    )

    return parser


def find_word(search_tearm: str):
    """
    Open a textfile and search for the given word.
    Show the number of words found.
    Show the total.
    Args:
        search_tearm:
            The word to search for
    """

    # It is good practice to use the with keyword when dealing with file objects.
    with open(FILE_NAME) as file_handle:

        for line in file_handle:
            line = line.rstrip()
            text_line = re.findall(
                search_tearm + "[^ ]*", line  # <- define your regex here
            )
            logger.debug(text_line)

            for w in text_line:
                found_words[w] = found_words.get(w, 0) + 1
                logger.debug(found_words)

    print("")
    word_count = 0
    total = 0
    for word, count in found_words.items():
        print(f"Searched word: {word}\n Count: {count}")
        word_count += 1
        total += count
    print("")
    print("Total number: {0}".format(total))


def main():
    """
    Invoke the parser and evaluate the result.
    """
    parser = get_parser()
    args = parser.parse_args()

    if args.word:
        find_word(args.word)
    elif args.version:
        print(f"Koalitionsvertrag - Version: {VERSION}")
    else:
        parser.print_help()


if __name__ == "__main__":
    # Create an empty dict for the words found
    found_words = dict()
    main()

Es werden folgende Bibliotheken importiert:

import re
import argparse
import logging  # optional

Da logging verwendet wird, beginnt der Code mit den folgenden Zeilen.

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger()

Wenn Ihr auf ein Logging verzichten möchtet, könnt Ihr auf diese Zeilen (und den entsprechenden Import) verzichten.

Nach dem Einrichten des Logging folgen zwei Konstanten. Von Bedeutung ist hier insbesondere der Name der zu lesenden Datei (hier: „koalitionsvertrag_2021.txt“).

VERSION = "1.0"
FILE_NAME = "koalitionsvertrag_2021.txt"  # <- Enter your file here.

Im Gegensatz zur ursprünglichen Version, ist dieses Skript strukturierter. So wurde argparse in eine separate Funktion get_parser() verlagert. Darüber hinaus habe ich (Google) Docstrings sowie die Angabe von Datentypen hinzugefügt. Letzteres ist seit Python 3.5 möglich. Es hilft Fehler zu vermeiden und macht den Code lesbarer.

Das Öffnen der Textdatei übernimmt jetzt

with open(FILE_NAME) as file_handle:

Es hat den Vorteil, dass das Schließen der Datei automatisch erfolgt. Damit ist ein f.closed überflüssig.

Das Öffnen der Datei, wie auch das anschließende Zählen des angegebenen Suchbegriffs, wird in der Funktion find_word() realisiert. Dabei wird get() genutzt, eine Methode, die bei einem Dictionary den Wert zum korrespondierenden Schlüssel zurückgibt. Daher kann sie dafür verwendet werden, die Anzahl von Schlüsseln in einem Dictionary zu zählen. In Code gegossen, sieht dies hier folgendermaßen aus:

for w in text_line:
    found_words[w] = found_words.get(w, 0) + 1
    logger.debug(found_words)

Wird zum Beispiel nach „SPD“ gesucht, führt dies zu folgender durch

logger.debug(found_words)

erzeugten Ausgabe:

DEBUG:root:{'SPD,': 1}
DEBUG:root:{'SPD,': 1, 'SPD': 1}
DEBUG:root:{'SPD,': 1, 'SPD': 2}
DEBUG:root:{'SPD,': 1, 'SPD': 3}
DEBUG:root:{'SPD,': 1, 'SPD': 3, 'SPD.': 1}

In dem Dictionary found_words kommt „SPD“ insgesamt fünfmal vor: 1 x mit dem Schlüssel „SPD,“, 3 x mit dem Schlüssel „SPD“ und 1 x mit dem Schlüssel „SPD.“

Der Aufruf des Skripts erfolgt mit

$ python3 count_words.py -w <Suchbegriff>

Zum Abschluss kommen wir noch zur Frage: Woher bekomme ich den Koalitionsvertrag 2021? Den könnt Ihr Euch zum Beispiel bei FragDenStaat (als PDF) herunterladen. Eine Fassung als reinen Text gibt es hier.