Lückentext ersetzen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
decoder
User
Beiträge: 12
Registriert: Dienstag 6. Oktober 2020, 11:18

decoder hat geschrieben: Sonntag 11. Oktober 2020, 11:34
__blackjack__ hat geschrieben: Samstag 10. Oktober 2020, 14:04 @decoder: Irgendwo auf dem Weg der Daten hat was mit der Kodierung nicht geklappt: "für" sollte wohl "für" heissen. Falls das beim Einlesen passiert: Bei Textdateien ist es wichtig, dass man beim öffnen die korrekte Kodierung angibt. Die Vermutung liegt nahe, dass hier eine UTF-8 kodierte Textdatei fälschlicherweise als CP1252 eingelesen wurde:

Code: Alles auswählen

In [56]: "für".encode("cp1252").decode("utf-8")                                
Out[56]: 'für'
Bei den Lückenworten sind ja noch Satzzeichen dran. Das geht natürlich nicht:

Code: Alles auswählen

In [58]: len("je")                                                             
Out[58]: 2

In [59]: len("__,")                                                            
Out[59]: 3

In [60]: does_match("__,", "je")                                              
Out[60]: False
Ich habe in meinem kleinen Testcode eine `fill()`-Funktion die als erstes Argument den kompletten Lückentext als Zeichenkette bekommt und (mit Hilfe einer weiteren Funktion) da nur die Lückenworte ohne Satzzeichen draus ermittelt. Für das ermitteln der Füllworte aus dem Lückentext sind reguläre Ausdrücke ganz praktisch. Also das `re`-Modul in der Standardbibliothek.

Deine Aufteilung des Lückentextes ist auch falsch: Du hast das letzte Wort zerteilt! Hast Du das manuell gemacht, oder ist das ein Fehler in den Eingangsdaten? Beziehungsweise hast Du das überhaupt falsch gemacht? Denn *mit* diesem Fehler dürft es keinen `IndexError` geben. Ohne den Fehler aber schon.

Um Lückenwort und Füllwort buchstabenweise zusammen durch zu gehen ist die `zip()`-Funktion nützlich. Und dann entweder eine Schleife, oder wenn man es kompakter möchte die `any()`-Funktion und ein Generatorausdruck.
Ok, danke! Ja das letztere Problem habe ich behoben!
Ich habe nochmals eine Frage ;D Funktioniert die Funktion "wort_buchstaben_vergleich" oder beziehungsweise könntest du mir den/ die Fehler verraten und funktioniert die Funktion "does_match", also kann ich das so auf die Worte anwenden? Ich danke dir nochmals!

def wort_buchstaben_vergleich (a,b):
q = -1
i = 0
z = 0
k = 0
ueberpruefung = False
while k < len(a) and len(b):
while i < len(a) and len(b):
q = q+1
while a[z][q] == b[z][q]:
ueberpruefung = True
if ueberpruefung == False:
print()
else:
return wort_buchstaben_vergleich
if z == len(a) and len(b):
z = z+1

def lange_ueberpruefen (a,b):
if len(a) == len(b):
return lange_ueberpruefen

def does_match (a,b):
if lange_ueberpruefen(a,b) and wort_buchstaben_vergleich(a,b):
return does_match
Sirius3
User
Beiträge: 18274
Registriert: Sonntag 21. Oktober 2012, 17:20

Lass das mit dem zitieren der ganzen Beiträge, die kann ja jeder lesen, weil sie direkt davor stehen.
Code packt man im Forum in Code-Tags </>.

Ob eine Funktion funktioniert, kannst Du doch einfach testen.
Funktionen sollten immer einen Rückgabewert haben, oder nie. `lange_ueberpruefen` und `does_match` geben entweder eine Funktionsobjekt oder implizit None zurück. Man würde einen Wahrheitswert erwarten:

Code: Alles auswählen

def laenge_ueberpruefen(a, b):
    if len(a) == len(b):
        return True
    return False
oder kurz:

Code: Alles auswählen

def laenge_ueberpruefen(a, b):
    return len(a) == len(b)
In `wort_buchstaben_vergleich` hast Du while-Schleifen, die entweder nie oder für immer laufen. Es muß ja irgendetwas innerhalb der Schleife passieren, dass sich die Bedingung ändert.
Geh am besten noch mal ein paar Schritte zurück und übe Schleifen, Funktionen und die Python-Grundlagen an einfacheren Aufgaben.
Benutzeravatar
__blackjack__
User
Beiträge: 14053
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Weil hier schon länger nix mehr kam, hier der Anfang meiner Lösung. Die vollständige `fill()`-Funktion welche den groben Ablauf enthält: Lückentextworte aus Lückentext holen, Abbildung von Lückentextwort auf Füllwort erstellen, und dann diese Abbildung verwenden um den Lückentext auszufüllen.

Von den entsprechenden Funktionen die in `fill()` aufgerufen werden zeige ich die Signaturen und die Dokumentation. Die auch jeweils ein Aufrufbeispiel mit Ergebnis enthält.

Code: Alles auswählen

#!/usr/bin/env python3


def get_cloze_words(cloze_text):
    """
    Hole Lückentextworte aus dem gegebenen Lückentext `cloze_text`.

    Ein Lückentextwort besteht aus einer Folge von alphanumerischen Zeichen und
    Unterstrichen für die Lücken.  Was ein alphanumerisches Zeichen ist, hängt
    von der entsprechenden Unicode-Klassifizierung ab.

    Returns
    -------

    cloze_words : set
        Die Lückentextworte aus dem gegebenen Lückentext.

    Examples
    --------

    >>> sorted(get_cloze_words("_h __, _a_ __r ___e __b___!"))
    ['__', '___e', '__b___', '__r', '_a_', '_h']
    """
    ...
    return ...


def replace_cloze_words(cloze_text, cloze_word_to_word):
    """
    Ersetze die Lückentextworte im gegebenen Lückentext `cloze_text` durch die
    passenden Füllworte gemäss der Abbildung in `cloze_word_to_word`.

    Examples
    --------

    >>> cloze_word_to_word = {
    ...     "_h": "oh",
    ...     "__r": "für",
    ...     "_a_": "was",
    ...     "___e": "eine",
    ...     "__b___": "arbeit",
    ...     "__": "je",
    ... }
    >>> replace_cloze_words("_h __, _a_ __r ___e __b___!", cloze_word_to_word)
    'oh je, was für eine arbeit!'
    """
    ...
    return ...


def map_cloze_words_to_words(cloze_words, words):
    """
    Bilde Lückentextworte auf Füllworte ab.

    Raises
    ------

    ValueError
        - Falls es Füllworte gibt die auf kein Lückentextwort passen,
        - falls es für ein Lückentextwort kein Füllwort mehr gibt,
        - oder falls keine eindeutige Lösung möglich ist.

    Examples
    --------

    >>> from pprint import pprint
    >>> pprint(
    ...     map_cloze_words_to_words(
    ...         ["__", "___e", "__b___", "__r", "_a_", "_h"],
    ...         ["arbeit", "eine", "für", "je", "oh", "was"],
    ...     )
    ... )
    {'__': 'je',
     '___e': 'eine',
     '__b___': 'arbeit',
     '__r': 'für',
     '_a_': 'was',
     '_h': 'oh'}
    """
    ...
    return ...


def fill(cloze_text, words):
    """
    Fülle den Lückentext `cloze_text` mit den gegebenen Füllworten `words`.

    Raises
    ------

    ValueError
        - Falls die Füllworte nicht paarweise verschieden sind,
        - falls es Füllworte gibt die auf kein Lückentextwort passen,
        - falls es für ein Lückentextwort kein Füllwort mehr gibt,
        - oder falls keine eindeutige Lösung möglich ist.

    Examples
    --------

    >>> fill("_h __, _a_ __r ___e __b___!", "arbeit eine für je oh was".split())
    'oh je, was für eine arbeit!'
    """
    if len(words) != len(set(words)):
        raise ValueError("Die Worte müssen paarweise verschieden sein.")

    cloze_words = get_cloze_words(cloze_text)
    cloze_word_to_word = map_cloze_words_to_words(cloze_words, words)
    return replace_cloze_words(cloze_text, cloze_word_to_word)
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
narpfel
User
Beiträge: 691
Registriert: Freitag 20. Oktober 2017, 16:10

Das Problem sah so aus, als würde Prolog sich gut dafür eignen:

Code: Alles auswählen

#!/usr/bin/env -S swipl -g main -t halt

:- use_module(library(yall)).

possible_words(Words) :-
    split_string(
        "er in zu Als aus Bett fand sich einem eines Samsa Gregor seinem \c
        Morgens Träumen erwachte unruhigen Ungeziefer verwandelt ungeheueren",
        " ", " ", Words
    ).

is_same_or_blank('_', _).
is_same_or_blank(Char, Char).

is_letter_or_underscore(Char) :- char_type(Char, csym).

is_word(Word) :- string_chars(Word, Chars), maplist(is_letter_or_underscore, Chars).

matches(PossibleWords, Word, Target) :-
    member(Target, PossibleWords),
    string_chars(Word, WordChars),
    string_chars(Target, TargetChars),
    maplist(is_same_or_blank, WordChars, TargetChars).

select_word(PossibleWords, Word, Target) :-
    matches(PossibleWords, Word, Target) *-> true; string_chars(Target, Word).

join(Strings, Result) :-
    maplist(string_chars, Strings, Chars),
    append(Chars, FlatChars),
    string_chars(Result, FlatChars).

groupby(Predicate, In, Out) :-
    maplist(
        [X, Result] >> (call(Predicate, X) -> Result = true-X; Result = false-X),
        In,
        Pairs
    ),
    group_pairs_by_key(Pairs, Groups),
    pairs_values(Groups, Out).

fill_in_blanks(PossibleWords, TextWithBlanks, Result) :-
    string_chars(TextWithBlanks, Chars),
    groupby(is_letter_or_underscore, Chars, WordsWithBlanks),
    maplist(select_word(PossibleWords), WordsWithBlanks, ResultWords),
    include(is_word, ResultWords, ChosenWords),
    % TODO: While `permutation` filters out solutions with duplicate words,
    % partial solutions are also prohibited. Something like `subset` with
    % duplicates is needed to support partial solutions.
    permutation(PossibleWords, ChosenWords),
    join(ResultWords, Result).

main :-
    possible_words(PossibleWords),
    TextWithBlanks =
        "__s __e___ _a___ e____ _____n_ _u_ _________ ____m__ ________, \c
        _a__ _r s___ _n _____m ___t _u ____m ___________ ______e___ _______e__.",
    fill_in_blanks(PossibleWords, TextWithBlanks, Result),
    write(Result), nl.
Das Programm kann nur vollständig lösbare Lückentexte lösen, aber dafür findet es alle möglichen Lösungen:

Code: Alles auswählen

?- fill_in_blanks(["foo", "bar", "baz"], "__o, _a_ b__!", Result).
Result = "foo, bar baz!" ;
Result = "foo, baz bar!" ;
false.
Benutzeravatar
__blackjack__
User
Beiträge: 14053
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ein weiteres kleines Häppchen: Das extrahieren der Lückentextworte mit Hilfe eines regulären Ausdrucks:

Code: Alles auswählen

import re

CLOZE_WORD_RE = re.compile(r"\w+")

def get_cloze_words(cloze_text):
    """
    Hole Lückentextworte aus dem gegebenen Lückentext `cloze_text`.
    
    Ein Lückentextwort besteht aus einer Folge von alphanumerischen Zeichen und
    Unterstrichen für die Lücken.  Was ein alphanumerisches Zeichen ist, hängt
    von der entsprechenden Unicode-Klassifizierung ab.
    
    Returns
    -------
    
    cloze_words : set
        Die Lückentextworte aus dem gegebenen Lückentext.
    
    Examples
    --------
    
    >>> sorted(get_cloze_words("_h __, _a_ __r ___e __b___!"))
    ['__', '___e', '__b___', '__r', '_a_', '_h']
    """
    return set(CLOZE_WORD_RE.findall(cloze_text))
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Natas0
User
Beiträge: 1
Registriert: Sonntag 22. November 2020, 16:27

Hast du inzwischen eine Lösung gefunden?
Antworten