Seite 1 von 1

While-Schleife funktioniert nicht wie gewollt

Verfasst: Freitag 25. Mai 2012, 19:03
von TheChiller
Hallo!
Anlässlich einer Programmierhausaufgabe, die ich schon zu 60% erledigt habe, muss ich mich mit dem Programmcode mal an Euch wenden.
Es geht darum, dass der Nutzer ein Wort angibt, das in einem Korpus, das als Datei reingeladen wird, gesucht wird. Dieses Wort, auch Token genannt, soll zusammen mit den fünf vorhergehenden und den fünf folgenden Wörtern (=Kollokation) ausgegeben werden.
Kommt das Wort aber häufiger vor, so soll das nächste Auftreten des Wortes im Korpus unter dem vorherigen mit einem Zeilenumbruch dazwischen ausgegeben werden.
Ich habe das dementsprechend programmiert und meine While-Schleife scheint die weiteren Befehle auch auszuführen (bis die Anzahl Zeilenumbrüche im abschließenden String, der ausgegeben wird, gleich der Vorkommen des gesuchten Wortes ist), aber wenn ein Wort mehrmals auftritt, wird es nicht an den String angefügt, der String enthält trotzdem nur die allererste Kollokation. Warum?
Das hier ist mein Programmcode und einen Ausschnitt aus der Textdatei, die das Korpus darstellt, habe ich angehängt (Wenn man für das zu suchende Wort 'supervision' eingibt, hat man nur 3 Treffer, daher ist das ganz passend).

Code: Alles auswählen

# coding=utf-8
from __future__ import division
import codecs

Korpus_original = codecs.open("poe.txt","r").read().split() #eventuell nach "poe.txt" noch ,"utf-8", anfügen
Korpus=Korpus_original[:]
suchwort=raw_input(u"Welches Wort soll im Korpus gesucht werden?\n")
Kollokationen=""
Fuenfvor=[]
Fuenfhinter=[]
list_suchwoerter= []
while (Kollokationen.count("\n"))<=Korpus.count(suchwort):
    #print "Anzahl Suchwörter im Korpus: ",Korpus.count(suchwort)
    # print "Nummer von Zeilenumbrüchen in Kollokationen",Kollokationen.count("\n")
    suchwortPos=Korpus.index(suchwort.lower())
    
    list_suchwoerter.append(suchwortPos)
    print list_suchwoerter
    #print Korpus[suchwortPos-5:suchwortPos] 
    for i in range (suchwortPos-5,suchwortPos):
        if Korpus[i] not in Fuenfvor and len(Fuenfvor)<5:
            Fuenfvor.append(Korpus[i])
            
        #    print "i", Korpus[i], Fuenfvor
    for i in range(suchwortPos,suchwortPos+5):                     
        if Korpus[i] not in Fuenfhinter and len(Fuenfhinter)<6:                                    
            Fuenfhinter.append(Korpus[i])
        #    print Fuenfhinter
    if suchwortPos in list_suchwoerter:
        del Korpus[suchwortPos]
        #print "EIN SUCHWORT GELÖSCHT"
    Kollokationen=" ".join(Fuenfvor)+" "+suchwort+" "+" ".join(Fuenfhinter[1:])+"\n" 
    
    #print Fuenfvor, suchwort, Fuenfhinter
    #Kollokationen=" ".join(Kollokationen)
print Kollokationen


Vielen Dank im Voraus :-)

Poe.txt (Das Korpus):
In the inmost recesses of this coppice not far from the eastern
or more remote end of the island Legrand had built himself a small
hut which he occupied when I first by mere accident made his
acquaintance This soon ripened into friendship for there was much
in the recluse to excite interest and esteem I found him well
educated with unusual powers of mind but infected with misanthropy
and subject to perverse moods of alternate enthusiasm and melancholy
He had with him many books but rarely employed them His chief
amusements were gunning and fishing or sauntering along the beach
and through the myrtles in quest of shells or entomological
specimens his collection of the latter might have been envied by a
Swammerdamm In these excursions he was usually accompanied by an old
negro called Jupiter who had been manumitted before the reverses of
the family but who could be induced neither by threats nor by
promises to abandon what he considered his right of attendance upon
the footsteps of his young Massa Will It is not improbable that
the relatives of Legrand conceiving him to be somewhat unsettled in
intellect had contrived to instil this obstinacy into Jupiter with
a view to the supervision and guardianship of the wanderer

The winters in the latitude of Sullivan 's Island are seldom very
severe and in the fall of the year it is a rare event indeed when a
fire is considered necessary About the middle of October 18- there
occurred however a day of remarkable chilliness Just before sunset
I scrambled my way through the evergreens to the hut of my friend
whom I had not visited for several weeks my residence being at
that time in Charleston a distance of nine miles from the Island
while the facilities of passage and re-passage were very far behind
those of the present day Upon reaching the hut I rapped as was my
custom and getting no reply sought for the key where I knew it was
secreted unlocked the door and went in A fine fire was blazing upon
the hearth It was a novelty and by no means an ungrateful one I
threw off an overcoat took an arm-chair by the crackling
logs and awaited patiently the arrival of my hosts

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Freitag 25. Mai 2012, 19:28
von BlackJack
@TheChiller: Falls ich richtig verstanden habe was Du haben möchtest, dann ist das alles superkompliziert gelöst. Das sollte man mit *einer* ``for``-Schleife zusammen mit der `enumerate()`-Funktion lösen können. In der Schleife prüft man das jeweilige Wort und wenn man einen Treffer hat holt man sich das Wort + Umgebung mittels „slicing” aus der Korpus-Liste.

Die einzelnen Treffer kann man schon zusammenfügen, aber dann in einer Liste sammeln. In Schleifen wiederholt Zeichenketten erweitern kann ineffizient werden. Der idiomatische Weg ist das Sammeln von Teil-Zeichenketten in einer Liste und am Ende ein zusammenfügen mittels der `join()`-Methode auf Zeichenketten.

Mach Dir mal klar wie oft bei Dir Sequenzen linear immer wieder und wieder durchlaufen werden. Bei jedem `index()`, Test mit ``in``, und ``del`` um ein Listenelement zu löschen wird viel unnötige Arbeit verrichtet.

Zu Deiner eigentlichen Frage eine Gegenfrage:

Code: Alles auswählen

spam = 'Hallo'
spam = ' Welt'
print spam
Was würdest Du hier als Ausgabe erwarten?

Edit: 'supervision' kommt nur einmal vor ist also kein gutes Beispiel für den Textausschnitt.

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Freitag 25. Mai 2012, 20:06
von TheChiller
Danke schon mal für deine Nachricht!

Die Ausgabe deines Beispiels ist ja klar. Und ich habe mir auch schon gedacht, dass sich meine Lösung sehr vereinfachen lässt. Habe es eben nur erstmal so aufgebaut, wie ich mir das Programm vorgestellt habe, ohne es zu vereinfachen. Kannst du mir ein Beispiel für die enumerate-Funktion geben? Die habe ich noch nie verwendet, daher habe ich es ja auf diesem Wege programmiert. Danke voraus!

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Freitag 25. Mai 2012, 20:11
von derdon
Ein Beispiel mit enumerate:

Code: Alles auswählen

>>> shopping_list = ['apples', 'flour', 'honey', 'bread']
>>> for i, item in enumerate(shopping_list):
...     print '{}: {}'.format(i, item)
... 
0: apples
1: flour
2: honey
3: bread

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Freitag 25. Mai 2012, 21:30
von Hyperion
@BlackJack: Man muss die "Text"-Liste aber dann noch um fünf leere Einträge zu Beginn erweitern, damit das auch bei Suchwörtern klappt, die in den ersten fünf Positionen stehen... oder gibt es da einen Slicing-Trick, den ich hier übersehe?

Ok, so was ginge wohl:

Code: Alles auswählen

text[max(0, index-5):index+5]
:-)

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Freitag 25. Mai 2012, 22:16
von BlackJack
@Hyperion: Stimmt, hatte ich gar nicht dran gedacht. Dafür ist bei Dir der obere Index um 1 zu klein. :-)

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Samstag 26. Mai 2012, 13:00
von Hyperion
BlackJack hat geschrieben:Dafür ist bei Dir der obere Index um 1 zu klein. :-)
Pedant :mrgreen: Ob nun vier oder fünf Wörter danach ist doch egal... :oops:

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Montag 28. Mai 2012, 02:49
von Leonidas
5 oder 4, das ist ja ein konstanter Faktor c und fällt unter den Tisch :D

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Montag 28. Mai 2012, 03:39
von TheChiller
Okay, ich frage mich nun nur, wie genau mir die enumerate-Funktion helfen soll. Reicht mir nicht schon das Slicing?
Und irgendwie versuche ich immer noch zu verstehen, warum meine allererste, dieses Thema eröffnende While-Schleife nicht funktioniert.

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Montag 28. Mai 2012, 06:29
von BlackJack
@TheChiller: Für das Slicing brauchst Du doch einen Index. Der kann vom `enumerate()` kommen.

Wenn die Ausgabe von meinem Beispiel klar ist, dann sollte auch klar sein warum Du nur eine Kollokation in Deiner ``while``-Schleife hast. Übrigens die *letzte* und nicht die *erste*. Du hast ja nicht gesagt *was* mein Beispiel ausgibt, darum hoffe ich mal Du gehst nicht davon aus, dass es 'Hallo Welt' ausgibt.

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Montag 28. Mai 2012, 12:37
von Hyperion
Ich bin mal nett und poste eine Lösung, die ich in einer Python-Shell entwickelt habe:

Code: Alles auswählen

In [33]: with open("poe.txt") as f:
   ....:     text = f.read().split()
   ....:     

In [35]: search = "is"

In [36]: result = list()

In [37]: for index, word in enumerate(text):
   ....:     if word == search:
   ....:         result.append(text[max(0, index-5):index+6])
   ....:         

In [51]: for item in result:
   ....:     print(" ".join(item))
   ....:     
his young Massa Will It is not improbable that the relatives
fall of the year it is a rare event indeed when
event indeed when a fire is considered necessary About the middle
Man sollte das alles natürlich noch hübsch in Funktionen verpacken. Die Suchfunktion ließe ich prima als Generatorfunktion schreiben :-)

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Montag 28. Mai 2012, 12:50
von BlackJack
Mein Testprogramm sah so aus:

Code: Alles auswählen

#!/usr/bin/env python


def main():
    with open('test.txt') as korpus_file:
        korpus = korpus_file.read().split()
    
    needle = raw_input('Welches Wort soll im Korpus gesucht werden? ')
    
    print '\n'.join(
        ' '.join(korpus[max(0, i-5):i+6])
        for i, w in enumerate(korpus)
        if w == needle
    )


if __name__ == '__main__':
    main()

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Montag 28. Mai 2012, 12:53
von Hyperion
Ja gut, ich wollte es Stück für Stück demonstrieren :-D

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Montag 28. Mai 2012, 17:47
von TheChiller
Ich hätte wirklich am Anfang, als ich begonnen habe, ein Programm für diese Aufgabe zu erstellen, nicht gedacht, dass es so viel kürzer und einfacher geht.
Und dank der Lösung von Blackjack habe ich endlich auch mal verstanden, auf welche Weise sich die enumerate-Funktion einbauen lässt (die Verbindung zum Suchwort (needle) und das ersetzen der index-funktion) :-)
Meine einzige letzte Frage, die ich noch habe, bezieht sich auf die letzten beiden Zeilen deines Programmcodes, Blackjack.
Da ich in Python noch nie eine main-Funktion gesehen habe (lediglich in C), frage ich mich, was genau die if-Abfrage if __name__ == '__main__': main() erwirkt. Wird dadurch die Main-Funktion erst ausgeführt?

Nochmals vielen Dank an alle, das bringt mich in Python wirklich weiter!

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Montag 28. Mai 2012, 18:12
von Hyperion
TheChiller hat geschrieben: Und dank der Lösung von Blackjack habe ich endlich auch mal verstanden,
Dir ist schon klar, dass BlackJacks und meine Lösung quasi identisch sind? ;-)
TheChiller hat geschrieben: Da ich in Python noch nie eine main-Funktion gesehen habe (lediglich in C), frage ich mich, was genau die if-Abfrage if __name__ == '__main__': main() erwirkt. Wird dadurch die Main-Funktion erst ausgeführt?
Wenn Du noch keine `main`-Funktion gesehen hast, dann hast Du Dir bisher noch nicht viele Programme angeschaut ;-)

Der Code bewirkt, dass Du ein unterschiedliches Verhalten des Moduls bekommst, je nach dem, wie es aufgerufen wird.

Wird es als Programm ausgeführt, so wird die `if`-Anweisung wahr und der Code im Rumpf entsprechend ausgeführt. Per Konvention ruft man dort eine `main`-Funktion auf, bei kleineren Dingen schreibt man den Code auch mal direkt in den Rumpf. Ich bevorzuge meist ersteres.

Wird das Modul hingegen aus einem anderen Modul importiert, so wird die Bedingung nicht wahr und es wird demzufolge auch nichts ausgeführt.

Du kannst das ganz einfach testen. Lege Dir ein Modul wie folgt an:

Code: Alles auswählen

#!/usr/bin/env python

print(__name__)
Nun führe es einmal aus:

Code: Alles auswählen

python main_hook.py
__main__
Aha. An den Namen `__name__` bindet der Interpreter in diesem Falle den String "__main__".

Nun importiere ich das Modul einmal in einer Python-Shell:

Code: Alles auswählen

>>> import main_hook
main_hook
In diesem Falle wird der Modulname an `__name__` gebunden.

Durch den "Trick" mit dem `if`-Statement kann ich also auf diese beiden unterschiedlichen Situationen reagieren. Bei einem Import will ich (idR.) keinen Code ausführen, starte ich ein Modul als "Programm", so will ich ja etwas ausführen.

Du solltest diesen "Hook" immer in Deine Module einbauen - außer, ein Modul soll nicht ausführbar sein, dann ist es natürlich unnötig.

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Montag 28. Mai 2012, 18:59
von TheChiller
Ah, sowas muss ja schließlich erst mal wissen, um mit Main-Funktionen umgehen zu können :)
Stimmt, ich habe noch nciht so viele Programme gesehen, da im Kurs im letzten Semester nur eine grobe Einführung gemacht wurde und jetzt erst richtige Programmierkenntnisse gefragt sind ;-)
Klar habe ich gemerkt, dass sich eure beiden Programme mehr als ähneln, nur finde ich die Version von Blackjack übersichtlicher (da ich u.a. das "In[33]" auch noch nie gesehen habe) :)

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Montag 28. Mai 2012, 19:07
von Hyperion
Du bist also mit Generator-Ausdrücken vertraut? Interessant... ;-)
TheChiller hat geschrieben: (da ich u.a. das "In[33]" auch noch nie gesehen habe) :)
Das ist nur der Prompt der Python Shell IPython.

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Montag 28. Mai 2012, 19:36
von TheChiller
Generator-Ausdrücke? Schon mal gehört :D

Achso, dachte schon, das "In [30]" sei eine unübliche Form der Zeileniteration :P

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Dienstag 29. Mai 2012, 02:27
von Leonidas
Hyperion hat geschrieben:
TheChiller hat geschrieben: (da ich u.a. das "In[33]" auch noch nie gesehen habe) :)
Das ist nur der Prompt der Python Shell IPython.
Deswegen würde ich abraten, IPython in Beispielen zu nutzen. Das verwirrt Anfänger und bis auf dass es zeigt "Hey, guckt mal was ich für ne tolle Shell habe" bringt es im Kontext von Foren nichts und man muss oft erklären was das überhaupt ist. Ich copypaste meine Beispiele meist aus ner Shell daher als Python-Quellcode, nicht als Transcripts.

Re: While-Schleife funktioniert nicht wie gewollt

Verfasst: Dienstag 29. Mai 2012, 04:39
von jerch
Mal mit einem anderen Ansatz

Code: Alles auswählen

>>> from collections import deque
>>> def kolok(it, word, pos=5, length=11):
...   ring = deque([None]*length)
...   for el in it:
...     ring.append(el)
...     ring.popleft()
...     if ring[pos]==word:
...       yield list(ring)
...   for _ in xrange(length-pos):
...     ring.append(None)
...     ring.popleft()
...     if ring[pos]==word:
...       yield list(ring)