Tekst genereren met Markovprocessen

Deze pagina bevat uitvoerbare code.

Opdracht: Tekst genereren met Markovprocessen

import random

# Dit notebook staat in solutions/ en het bestand in practicals/assets/,
# vandaar het pad terug. In de opgave zelf is dat gewoon "a.txt".
A_TXT = "../practicals/assets/a.txt"


def create_dictionary(filename):
    """Maakt een dictionary die per woord bijhoudt welke woorden erop volgen

    :param filename: de naam van het tekstbestand om te analyseren
    :type filename: str
    :rtype: dict
    """
    with open(filename) as file:
        text = file.read()

    words_follow = {}
    previous_word = "$"

    for new_word in text.split():
        if previous_word not in words_follow:
            words_follow[previous_word] = [new_word]
        else:
            words_follow[previous_word] += [new_word]

        previous_word = "$" if new_word[-1] in ".?!" else new_word

    return words_follow


assert create_dictionary(A_TXT) == {
    "krijg": ["toch"],
    "voor": ["de"],
    "wil": ["taarten", "42"],
    "toch": ["spam"],
    "Ik": ["wil", "krijg", "wil"],
    "spam": ["en"],
    "42": ["en", "taarten!"],
    "$": ["Ik", "Ik", "Ik"],
    "taarten": ["en", "voor"],
    "de": ["vakantie?"],
    "en": ["42", "spam.", "taarten"],
}

previous_word begint bij het startsymbool "$", en elk woord dat op een zin-einde volgt (., ? of !) zet previous_word daar weer op terug. Zo komt elk zinsbegin in de lijst bij "$" terecht, precies zoals het college en de opgave het beschrijven.

De test hierboven is exact het voorbeeld uit de opgave: create_dictionary('a.txt') levert de dictionary op die daar staat.

def generate_text(words_follow, n_words):
    """Genereert een tekst van n_words woorden met een Markovproces

    :param words_follow: dictionary met woordovergangen, van create_dictionary
    :type words_follow: dict
    :param n_words: het aantal woorden dat gegenereerd moet worden
    :type n_words: int
    :rtype: str
    """
    previous_word = "$"
    words = []

    for _ in range(n_words):
        new_word = random.choice(words_follow[previous_word])
        words.append(new_word)
        previous_word = "$" if new_word[-1] in ".?!" else new_word

    return " ".join(words)


generate_text(create_dictionary(A_TXT), 20)
'Ik wil 42 en taarten voor de vakantie? Ik krijg toch spam en 42 taarten! Ik wil 42 taarten! Ik'

generate_text draait zonder assertion: de uitvoer is willekeurig, dus er is geen vaste uitkomst om tegen te toetsen. Wat je wel kunt controleren, is of de cel foutloos uitvoert en of de uitvoer alleen woorden bevat die ook echt in words_follow voorkomen - en dat volgt direct uit hoe de functie is opgebouwd: elk woord komt uit words_follow[previous_word], nooit ergens anders vandaan.