Reimsuche im Text

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.
Antworten
systemraedchen
User
Beiträge: 2
Registriert: Montag 21. Mai 2012, 12:01

Hallo,

ich programmiere seit etwa 4 Wochen mit Python und es ist auch meine erste Programmiersprache. Nun wollte ich ein Programm schreiben, das in einen eingegeben Text schaut, welche Wörter sich reimen also die letzten 3 Buchstaben gleich sind. Leider schein ich irgendwas falsch gemacht zu haben, weil ich immer nur eine leere Liste ausgespuckt bekomme.

Code: Alles auswählen

import string

text = raw_input("Geben Sie bitte ihren Text ein! ")

text = text.replace(".", "")
text = text.replace(",", "")
text = text.replace("!", "")
text = text.replace("?", "")
text = text.split()
text = list(set(text))

reim = []
reim_help = []
i = 0
j = 0
while i >= len(text):
    x = text[i]
    reim_help.append(x)
    while j >= len(text):
        y = text[j]
        if x[-3:-1] == y[-3:-1]:
            reim_help.append(y)
            text.remove(y)
        else:
            j = j + 1
    text.remove(x)
    reim.append(reim_help)
    reim_help = []

print(reim)
Über Tipps und Verbesserungsvorschläge von eurer Seite würde ich mich sehr freuen.

Liebe Grüße,
systemraedchen

PS: Ich bin neu im Forum und weiß nicht, ob ich hier an der richtigen Stelle gelandet bin.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Das ist die richtige Stelle und willkommen im Forum.

Ich vermute, dass es nicht funktioniert, weil "x[-3:-1]" nicht die drei letzten Zeichen sind, sondern das drittletzte bis zum vorletzten. Benutze "x[-3:]".

Stefan
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Hallo und Willkommen im Forum!

Ich habe Deine Frage mal ins "Allgemeine" Forum verschoben. Das Ideen Forum ist eher als Ort für Brainstorming für Projektideen zu verstehen.

Zu Deiner Frage: Ich würde das alles anders angehen. Du schreibst imho zu viel Code, *ohne* die einzelnen Stücke separat zu testen.

Alleine Deine Extraktion der letzten drei Buchstaben aus einem String ist falsch. Das hätte Dir auch ohne den gesamten Code drum herum in einer Python-Shell schnell auffallen können:

Code: Alles auswählen

In [2]: x = "Hallo"

In [3]: x[-3:-1]
Out[3]: 'll'

In [4]: x[-3:]
Out[4]: 'llo'
(Ich verwende IPython als Shell - daher die [nummer]-Syntax statt ">>>", nicht verwirren lassen!)

Ich würde auch die Schleife vereinfachen. Im Endeffekt ist es ja richtig, dass Du jedes Element mit jedem anderen vergleichen musst. Ich würde aber mit `set.pop` (oder eben `list.pop`) arbeiten. Damit hast Du als äußere Schleife im Grunde das hier:

Code: Alles auswählen

while words:
    first = words.pop()
Als nächstes iterierst Du *direkt* über die verbliebenen Elemente Deiner Wörterliste und vergleichst die Endung beider Wörter:

Code: Alles auswählen

while words:
    first = words.pop()
    for second in words:
        if first[-3:] == second[-3:]:
            reim.add(first)
            reim.add(second)
`reim` sollte auch ein Set sein, da Du ansonsten evtl. Duplikate einträgst.

Im Grunde war es das dann auch schon.

Zu Deinem Code fällt mir noch folgendes auf:

- Du schreibst `print` im Code wie eine Funktion, benutzt aber offensichtlich (`raw_input`!) Python 2.x. Das solltest Du nicht tun! `print` ist da ein Statement und die runden Klammern haben da nichts zu suchen. Woher hast Du das?

- Du importierst `string`, ohne das Modul zu nutzen. Du kannst so etwas mittels des Tools `pyflakes` herausfinden:

Code: Alles auswählen

nelson@destiny ~/src/Python/forum/reim % pyflakes reim.py
reim.py:1: 'string' imported but unused
Generell solltest Du nur Module importieren, die Du auch nutzt.

- Du kannst Aufrufe schachteln:

Code: Alles auswählen

text = text.replace(".", "")
text = text.replace(",", "")
text = text.replace("!", "")
text = text.replace("?", "")
text = text.split()
kann man vereinfachen zu:

Code: Alles auswählen

text = text.replace(".", "").replace(",", "")...# usw
Oder aber noch besser, eine Schleife benutzen:

Code: Alles auswählen

In [20]: text = "Hallo, Welt!"

In [21]: for char in ".,?!":       
    text = text.replace(char, "")
   ....:     

In [22]: text
Out[22]: 'Hallo Welt'
- Namen sollten nicht ständig für andere Objekte benutzt werden. `text` ist bei Dir erst ein String, dann eine Liste... das ist nicht wirklich gut, da es das Lesen des Codes erschwert. Mein `words` sagt da doch viel eher aus, dass es sich um eine Wort-Liste handelt, oder? ;-)

Generell ist das Eingeben eines langen Textes per `raw_input` so eine Sache... wieso versuchst Du nicht, den Text per Kommandozeilenparameter aus einer Datei oder noch besser aus `sys.stdin` zu lesen? Aber zunächst solltest Du Dein Script debuggen und verbessern. Dazu kann man ruhig mal einen statischen Text im Programm selber platzieren! ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

So, ich habe mal so ein Script selber implementiert. Dabei fiel mir auf, dass man die Reime ja möglichst in Form eines Dictionaries mit den Endungen als Schlüssel und den diese beinhaltenden Wörter als Wert haben möchte.

Als Beispiel dient mir das Gedicht "Abendsonne" von Goethe :-)

Mir fiel auf, dass man die beiden verschachtelten Schleifen weg optimieren kann. In meinem alten Code (den ich als `get_rhymes_old` mal als Anschauungsdemo drinnen gelassen habe), hatte ich eine Laufzeit O(n * (n-1)) mit "n" als Anzahl Wörter im Text.

Im Grunde geht es aber ja nur darum, mindestens zwei Wörter zu haben, die dieselbe Endung aufweisen. Das kann ich aber bereits in zwei Durchläufen erreichen. Zunächst sammele ich *alle* Endungen und damit *alle* Wörter ein. Anschließend übernehme ich in einem zweiten Durchlauf nur diejenigen Endungen-Wörter-Paare, bei denen mehr als nur ein Wort im "Value" auftauchen (s. Dict-Comprehension). Das ist deutlich effizienter und hat als Laufzeit nur O(2n).
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
systemraedchen
User
Beiträge: 2
Registriert: Montag 21. Mai 2012, 12:01

Danke! Danke! Danke! Mit euren Tipps habe ich jetzt genau das Resultat, was ist wollte!

Code: Alles auswählen

text = "Ich bin eine Maus und ich wohn mit einer Laus in einem Haus."

text = text.replace(".", "").replace(",", "").replace("!", "").replace("?", "")
words = text.split()
words = list(set(words))

reim = []
reim_help = []
element1 = words[0]
element2 = words[0]

for element1 in words:
    reim_help.append(element1)
    for element2 in words:
        if element1 != element2 and element1[-3:] == element2[-3:]:
            reim_help.append(element2)
            words.remove(element2)
    reim.append(reim_help)
    reim_help = []

print reim
BlackJack

@systemraedchen: Die Zuweisungen an `element1` und `element2` vor der Schleife sind unsinnig und lassen das Programm zudem noch mit einer Ausnahme abbrechen wenn keine Worte eingegeben wurden.

Die Zuweisung an `reim_help` vor der Schleife kann und sollte man vermeiden in dem man den Code in der Schleife anders anordnet.

Und zu guter letzt entfernst Du Elemente aus einer Datenstruktur innerhalb einer Schleife in der Du über diese Struktur iterierst. Damit ist das Programm fehlerhaft, denn es ist dann nicht mehr sichergestellt, dass die Schleifen alle Worte erwischen.
Antworten