@LRK: Vielleicht mal als Anregung wie man so ein Problem in kleinere Teilprobleme zerlegen und die dann mit kleinen Funktionen lösen kann, und wie man bei der Entwicklung vorgehen kann. Damit es keine Lösung ist, die man einfach so kopieren kann, weil das sehr nach Hausaufgaben aussieht, verwende ich die Programmiersprache
Hy. Das ist ein Lisp-Dialekt der in Python implementiert ist, und auch alle Module und Packages verwenden kann, die das Python mit dem man das Hy-Programm ausführt, verwenden kann.
Als erstes muss man sich die Eingabedaten und das Ergebnis klar machen. Eingaben gibt es zwei: Die Datei mit den Worten und die Datei mit den Sätzen. Die mit den Sätzen soll Zeile für Zeile in eine neue Datei transformiert werden, wobei auch Sätze herausgefiltert werden sollen.
Da man immer nur einen Satz zur gleichen Zeit betrachten muss, und jeden nur ein einziges mal, sind die Sätze der Teil der Eingabe die nicht gleich am Anfang komplett in den Speicher geladen werden muss. Die Worte braucht man dagegen bei der Entscheidung ob eine Zeile behalten werden soll, also für jede Zeile erneut, darum sind das Daten die man in den Speicher laden sollte, statt sie immer wieder neu einzulesen.
Programmentwicklung passiert in der Regel Schritt für Schritt, wobei man mit jedem Schritt versucht dem Ergebnis näher zu kommen und jeden Schritt testet.
Der erste Schritt ist das einlesen der Daten. Dafür könnte man sich eine Funktion schreiben die einen Generator über die Zeilen einer Datei liefert, deren Dateinamen man der Funktion übergibt. Im Hauptprogramm kann man zum Testen dann erst einmal die Zeilen in einer Liste sammeln und mit `print` ausgeben. Am Anfang noch ein paar Konstanten definiert für die Dateinamen und die Kodierung der Textdateien, könnte das so aussehen:
Code: Alles auswählen
#!/usr/bin/env hy3
(import [contextlib [closing]])
(setv *sentences-filename* "Satz.txt"
*words-filename* "Liste.txt"
*result-filename* "SatzNeu.txt"
*encoding* "UTF-8")
(defn create-line-generator [filename]
(with [lines (open filename "r" :encoding *encoding*)]
(yield-from lines)))
(defmain [&rest args]
(with [sentences (closing (create-line-generator *sentences-filename*))]
(->> (list sentences)
(print))))
Als nächstes müssen wir die ungewünschten Sätze rausfiltern. Fangen wir mit denen an die "Freunde" enthalten. Dafür kann man sich eine Funktion schreiben die testet ob dieses Kriterium erfüllt ist, und das dann mit `remove` auf die Sätze anwenden:
Code: Alles auswählen
(defn contains-friends? [sentence]
(in "Freunde" sentence))
(defmain [&rest args]
(with [sentences (closing (create-line-generator *sentences-filename*))]
(->> (remove contains-friends? sentences)
((comp print list)))))
Und schon hat man die Sätze mit "Freunde" nicht mehr im Ergebnis.
Als nächstes ein Positiv-Filter, nämlich nur noch Sätze ins Ergebnis durchlassen, die mindestens ein Wort aus ``Liste.txt`` enthalten. Dazu müssen wir die Worte erst einmal einlesen. Das erledigt eine Funktion die alle Zeilen in eine Liste einliest und dabei die Zeilenendezeichen entfernt:
Code: Alles auswählen
(defn load-words [filename]
(with [lines (closing (create-line-generator filename))]
(lfor line lines (.rstrip line))))
Wenn man die Worte hat, kann man eine Funktion schreiben, die testet ob mindestens eines der Worte im Satz vorkommt:
Code: Alles auswählen
(defn contains-any-of? [words sentence]
(any (map (fn [word] (in word sentence)) words)))
Und die beiden Funktionen in die Hauptfunktion integriert sorgt dafür, dass nur noch die gewünschten Sätze im Ergebnis sind:
Code: Alles auswählen
(defmain [&rest args]
(with [sentences (closing (create-line-generator *sentences-filename*))]
(->> (remove contains-friends? sentences)
(filter (partial contains-any-of? (load-words *words-filename*)))
((comp print list)))))
Jetzt können die übriggebliebenen Sätze verändert werden. Dazu wieder eine kleine Funktion die einen Satz verändert:
Code: Alles auswählen
(defn modify-sentence [sentence]
(.replace sentence "ist" "kann"))
Die kann man jetzt im Hauptprogramm auf jeden übriggebliebenen Satz anwenden:
Code: Alles auswählen
(defmain [&rest args]
(with [sentences (closing (create-line-generator *sentences-filename*))]
(->> (remove contains-friends? sentences)
(filter (partial contains-any-of? (load-words *words-filename*)))
(map modify-sentence)
((comp print list)))))
Bleibt zum Schluss nur noch das wegschreiben in eine Datei. Wie gehabt, mit einer kleinen Funktion die das sammeln in einer Liste und das Ausgeben per `print` im Hauptprogramm ersetzt:
Code: Alles auswählen
(defn save-sentences [filename sentences]
(with [file (open filename "w" :encoding *encoding*)]
(.writelines file sentences)))
Führt zu folgendem Gesamtprogramm:
Code: Alles auswählen
#!/usr/bin/env hy3
(import [contextlib [closing]]
[functools [partial]])
(setv *sentences-filename* "Satz.txt"
*words-filename* "Liste.txt"
*result-filename* "SatzNeu.txt"
*encoding* "UTF-8")
(defn create-line-generator [filename]
(with [lines (open filename "r" :encoding *encoding*)]
(yield-from lines)))
(defn contains-friends? [sentence]
(in "Freunde" sentence))
(defn load-words [filename]
(with [lines (closing (create-line-generator filename))]
(lfor line lines (.rstrip line))))
(defn contains-any-of? [words sentence]
(any (map (fn [word] (in word sentence)) words)))
(defn modify-sentence [sentence]
(.replace sentence "ist" "kann"))
(defn save-sentences [filename sentences]
(with [file (open filename "w" :encoding *encoding*)]
(.writelines file sentences)))
(defmain [&rest args]
(with [sentences (closing (create-line-generator *sentences-filename*))]
(->> (remove contains-friends? sentences)
(filter (partial contains-any-of? (load-words *words-filename*)))
(map modify-sentence)
(save-sentences *result-filename*))))
In Python kann man bei der Entwicklung grundsätzlich genau so vorgehen. Da Hy recht nah dran ist an Python, würde das Programm sogar sehr ähnlich aussehen.