Textdatei durchsuchen

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.
flummi
User
Beiträge: 33
Registriert: Samstag 28. April 2012, 13:33

Also,

ich habe hier mehrere endlose Textdateien in denen PokerHände protokolliert sind. Ich will nun folgende funktion haben:

zunächst soll eine eingabe erfolgen, um einen zu untersuchenden spieler zu spezifizieren (sprich eine hand soll nur untersucht werden wenn dieser spieler an dieser beteiligt war)

dann soll falls der spieler beteiligt ist, die statistiken aufgenommen werden.

Ich weiß, dass das bereits holdem manager etc. macht aber mich interessiert a) wie das mit python umgesetzt wird. und b) möchte ich später zusätzliche Suchfunktionen einbinden. c) ich bastle dann noch an nem grafischen interface und lern noch mehr

hier ist das format:

PokerStars Game #76620334109: Hold'em No Limit ($0.05/$0.10 USD) - 2012/03/04 6:53:25 ET
Table 'Eukrate V' 6-max Seat #6 is the button
Seat 1: Schlienz ($14.98 in chips)
Seat 2: vitastarrr ($31.89 in chips)
Seat 3: pilka2007 ($10.30 in chips)
Seat 4: reXne ($10.45 in chips)
Seat 5: Aren_b22 ($4 in chips)
Seat 6: zombewaz ($6.25 in chips)
Schlienz: posts small blind $0.05
vitastarrr: posts big blind $0.10
*** HOLE CARDS ***
pilka2007: folds
reXne: folds
Aren_b22: folds
zombewaz: folds
Schlienz: raises $0.20 to $0.30
vitastarrr: calls $0.20
*** FLOP *** [5c 8h 8s]
Schlienz: bets $0.34
vitastarrr: calls $0.34
*** TURN *** [5c 8h 8s] [Td]
Schlienz: checks
vitastarrr: bets $0.73
Schlienz: folds
Uncalled bet ($0.73) returned to vitastarrr
vitastarrr collected $1.22 from pot
*** SUMMARY ***
Total pot $1.28 | Rake $0.06
Seat 2: vitastarrr collected ($1.22)



PokerStars Game #76620327244: Hold'em No Limit ($0.05/$0.10 USD) - 2012/03/04 6:52:45 ET
Table 'Repsolda V' 6-max Seat #6 is the button
Seat 1: Dimedr.All ($10 in chips)
Seat 2: fffqqq ($23.98 in chips)
Seat 3: FrEaKnR1 ($10 in chips)
Seat 4: strikse ($10.15 in chips)
Seat 5: keane_mark2 ($16.81 in chips)
Seat 6: vgerman ($12.43 in chips)
Dimedr.All: posts small blind $0.05
fffqqq: posts big blind $0.10
*** HOLE CARDS ***
FrEaKnR1: folds
strikse: folds
keane_mark2: folds
vgerman: folds
Dimedr.All: folds
Uncalled bet ($0.05) returned to fffqqq
fffqqq collected $0.10 from pot
*** SUMMARY ***
Total pot $0.10 | Rake $0
Seat 2: fffqqq collected ($0.10)

und das geht endlos so weiter... in mehreren dateien, bin über jede hilfe dankbar, hab zwar ein paar python bücher gelesen bin aber zu blöd um daraus schlau zu werden. muss hier hierfür am besten eine klasse definieren?
flummi
User
Beiträge: 33
Registriert: Samstag 28. April 2012, 13:33

also der ansatz ist mir schon klar, aber ich hab kA wie das genau funktioniert....

im prinzip sind alle hände durch eine leerzeile getrennt, das muss ich irgendwie ausnutzen, oder dass die nächste hand mit einem schlüsselwort beginnt...

es gibt eine unbestimmte anzahl an zeilen die mit seat x beginnen und falls dort nie der name des zu untersuchenden spielers auftaucht braucht die hand nicht weiter gelesen zu werden und man springt zur nächsten...

auch die anderen Straßen werden eigtl klar angekündigt sowie was die spieler machen...

eingaben krieg ich mit raw_input () und textsuchen mit find ()

aber wie genau geht das jetzt?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Also dafür müsste man einen Parser entwickeln, der diese "Sprache" parsen kann. Anschließend kann man sich dann die relevanten Daten herauspicken und verarbeiten.

Dafür kann man Module wie pyparsing oder LEPL verwenden. Oder, wenn man sma heißt, sich from scratch selber einen schreiben :-D

Allerdings scheinst Du in Sachen Python eher wenig erfahren und zudem empfinde ich das Thema "Parser entwickeln" als eher schwierig. Ob Du also bei dieser Aufgabe glücklich und nicht überfordert wirst, wage ich zu bezweifeln...

Nebenbei: Sehe ich das nur nicht, oder fehlen da komplett die Angaben über die "Hände"? Ich sehe da nur Namen und Gebote...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
flummi
User
Beiträge: 33
Registriert: Samstag 28. April 2012, 13:33

ich hab die Hände anonymisiert... gut, ich will unbedingt diesen Parser schreiben, mache gerade meine Bachelorarbeit in Chemie bin also nicht ganz dumm. Aber du hast recht ich habe null Erfahrung ,) Hab aber letzten Monat zwei Bücher gelesen, weiß also grob wie das funktioniert.

was bringen diese Parsermodule. welchen vorteil habe ich, wenn ich nicht einfach bei 0 anfange, was ist so die grundidee eines parsers. und welcher ist möglichst simpel, reicht aber für meine anwendung und hat eine open source sodass ich diese erstmal lesen könnte, oder ist diese zu lang um sie zu lesen?

sprich, kannst du mir etwas genauer den weg weisen?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

flummi hat geschrieben: sprich, kannst du mir etwas genauer den weg weisen?
Mach Dich einfach mal schlau :-) Du kannst per google sicherlich Dokumente über den Sinn von Parsern finden und auch über die Vor- und Nachteile von Parsergeneratoren.

Anschaulich hat unser User sma das ein oder andere Video-Tutorial gemacht:

http://vimeo.com/8297457
http://vimeo.com/8407944

Ich denke damit hast Du schon einen Brocken zu tun :-)

Ach ja, bei den Libs, die ich verlinkte, sind auch Tutorials dabei. Auch da werden die Grundbegriffe erklärt.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

flummi hat geschrieben:welchen vorteil habe ich, wenn ich nicht einfach bei 0 anfange?
Du erfindest nicht das Rad neu, wirst eine robustere Basis zum Arbeiten haben und kannst deine Zeit nach der anfänglichen Einarbeitungsphase voll und ganz darauf konzentrieren die Ausgabe des Parsers weiterverarbeiten zu können anstatt dich mit den Problemen deiner eigenen Umsetzung herumschlagen zu müssen.

Bin ich eigentlich der einzige für den das Unterfangen hier leicht nach Pokerbot klingt?
flummi
User
Beiträge: 33
Registriert: Samstag 28. April 2012, 13:33

Für einen Pokerbot brauch ich nur PIL und OCR, Holdem Manager könnt ich Parallel laufen lassen, und die Informationen direkt aus dem Bild saugen.... dafür brauch ich das nicht was ich gerade frage.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

flummi hat geschrieben:Für einen Pokerbot brauch ich nur PIL und OCR, ...
Naja, einen Text parsen ist viel einfacher, als diese Infos erst aus Bildmaterial zu generieren. Ich weiß ja nicht, wie man an dieses Log kommt... wenn das in Echtzeit verfügbar ist, dann ist das doch genau das, was man für einen Bot braucht. Insofern ist Deine Argumentation hier "dünn"...

Aber im Grunde ist das ja eh Offtopic.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
flummi
User
Beiträge: 33
Registriert: Samstag 28. April 2012, 13:33

naja wenn man sowieso schon seine eigene Hand auslesen muss, dann kann man die restlichen daten auch aus bild nehmen...

und nein es gibt die daten nicht genau echtzeit, die log wird eine hand NACH der hand generiert. daher weiss man ohne pil nie wer was bzw wie viel setzt, nur "fast" aktuelle Statistiken der spieler.

also so dünn ist die argumentation nicht.

pyparsing gefällt mir, denke damit kann ich arbeiten.
BlackJack

@flummi: Grundlagen Übersetzerbau, wo Parser einen grossen Anteil dran haben ist in der Informatik normalerweise eine eigene Vorlesung. Und baut auf Grammatiken aus der Grundlagenvorlesung zur Theoretischen Informatik auf. Wenn man das selber umsetzen möchte, muss man halbwegs Programmieren können. Mindestens mit Rekursion sollte man sicher umgehen können. In einem Monat zwei Bücher lesen bringt einen IMHO nicht wirklich auf den Stand. Weder vom Wissen, noch von der Erfahrung. Darum nimmt man besser einen fertigen Parser. :-) Sofern der nötig ist.

Ich denke Du müsstest Dir über zwei Strukturen klar werden. Die Struktur, welche die Daten in Deinem Programm haben sollen. Also welche Daten brauchst Du, welche Operationen werden darauf ausgeführt, und wie organisiert man die Daten dafür am besten in Datentypen.

Die andere Struktur, die Du erfassen musst ist das Datenformat Deiner Textdateien. Welche Daten sind enthalten (sollte idealerweise eine Untermenge von denen sein, die Du benötigst ;-)), und wie sind die Dateien vom Muster her aufgebaut.

Dann kannst Du entscheiden wie Du da am besten heran gehst. Selber auseinander pflücken, mit einem selbst geschriebenen Parser. Wie sauber muss der sein, also reicht eventuell auch eine Mischung aus Eingabe in Zeilenblöcke zerlegen und die dann entweder weiter zerlegen und einzelne oder mehrere Zeilen mit regulären Ausdrücken und Zeichenkettenoperationen verarbeiten. Oder kann man einfacher eine Bibliothek zum erstellen eines Parsers für das gesamte Format schreiben.

Wenn keine „Einzelwerte” vorkommen, die über mehrere Zeilen gehen, könnte man vielleicht mit einem Parser für einzelne Zeilen und einem selbst implementierten Zustandsautomaten auskommen.

@webspider: Nein, Du bist nicht der einzige. Laut geäussert hat diese Vermutung auch schon Leonidas im Thema Bidschirmausgabe abgreifen von flummi.

Ich frage mich ob Chemiestudenten heutzutage nicht mehr in der Lage sind synthetische Drogen zusammen zu kochen, dass sie auf *solche* Mittel zur Geldbeschaffung zurück greifen müssen. :twisted:
problembär

PokerHände ... beschmieren Tisch und Wände. :P

Hab' ja eigentlich kein Interesse, bei einem Bot zu helfen.
Ich weiß auch nicht, was Du genau auswerten willst.
Aber natürlich kannst Du mit dem Format jedes Spiel von dem nächsten trennen, und darin die Spielzüge jedes Spielers extrahieren. Steht ja immer der Spielername am Zeilenanfang. Mußt nur noch am ":" splitten.

Eine Klasse "Game" und eine Klasse "Player" wäre wohl sinnvoll. Aber man kann's auch ohne OOP machen.
Ob man das jetzt "Parser" nennt, sei mal dahingestellt.
Jedenfalls ist "oh, da müßte ich erst einen Parser schreiben, also laß' ich's ganz" schonmal kein Argument.
flummi
User
Beiträge: 33
Registriert: Samstag 28. April 2012, 13:33

Was ist eigtl. dagegen einzuwenden ausschließlich mit

string.readline ()
string.split ()

usw. zu arbeiten?

gibts eine doppelte split funktion, also dass ich einen string zwischen zwei zeichen kriege, die ich wählen kann?
BlackJack

@flummi: Gegen `str.readline()` spricht, dass es die Methode nicht gibt. ;-) Gegen `file.readline()` spricht, dass es (fast) das selbe ist wie die `file.next()`-Methode und diese nicht nur auf Dateien, sondern auf jedem Iterator existiert. Damit wäre der Code flexibler, weil statt eines Dateiobjektes auch jeder andere Iterator funktioniert, der Zeilen liefert.

Gegen `str.split()` & Co spricht, dass es nur bei recht einfachen Formaten zu Quelltext führt, der noch übersichtlich und verständlich ist, weil der Code zu lang und komplex wird. Reguläre Ausdrücke (`re`-Modul) haben das umgekehrte Problem — da wird der Code bei komplexeren Formaten zu *kurz* und komplex um ihn gut verstehen zu können. Während Parser-Bibliotheken in der Lesbarkeit ganz gut skalieren, also sowohl bei einfachen als auch komplexen Formaten ganz gut lesbar sind, ist es mit Kanonen auf Spatzen geschossen, wenn das Eingabeformat und das Zielformat eher einfach sind.

Es kommt also ganz auf die Eingabe und gewünschte Ziel an, ob „per Hand”, reguläre Ausdrücke, oder Parser, oder eben auch eine sinnvolle Kombination aus diesen Ansätzen, eine gute Lösung darstellen.

Die „doppelte split funktion” gibt es nicht fertig. Die müsste man sich selbst implementieren. Entweder tatsächlich mit zwei `split()`\s, oder mit `str.index()` und Slicing. Oder man verwendet dafür einen regulären Ausdruck.
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

Das andere Problem ist, dass so einfache Lösungen wahrscheinlich nicht robust genug sein werden um deine Eingabe korrekt zu verarbeiten und bei dem Aufwand den du brauchst das hinzubiegen du mit einem Parser dann doch besser beraten wärst.

Vielleicht erlernst du ja aber auch erst einmal richtig Python und schaust dann weiter :wink:
flummi
User
Beiträge: 33
Registriert: Samstag 28. April 2012, 13:33

Was ist der unterschied zwischen str.index und str.find?
Wie funktioniert diese Methode? Was bringt mir der Index? kann ich an einem bestimmten index splitten? wie geht das?

ich hab mir folgendes gebastelt, diese funktion soll doppelt splitten.

Code: Alles auswählen

def strfromstr (stri, char1, char2):
    stri = stri.split (char1)
    stri.pop (0)
    stri = str (stri)
    stri = stri.split (char2)
    stri.pop (1)
    stri.pop (1)
    stri.pop (1)
    stri = str (stri)
    stri = stri.strip ("[\"']")
    print stri
funktioniert allerdings nur für die erste zeile einer hand um die handnummer herauszufinden.
ich muss stri.pop (1) solange ausführen solange entweder kein fehler ausgespuckt wird, und falls fehler dann trotzdem mit dem code fortfahren, oder stri.pop (1) solange die liste 2 oder mehr elemente hat.

wie mach ich das jetzt am besten?
Zuletzt geändert von Hyperion am Freitag 11. Mai 2012, 12:36, insgesamt 1-mal geändert.
Grund: Code in Python-Code Tags gesetzt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

flummi hat geschrieben:Was ist der unterschied zwischen str.index und str.find?
Ok, ich lese mal die Doku für Dich vor:
Doku hat geschrieben: str.index(sub[, start[, end]])
Like find(), but raise ValueError when the substring is not found.
flummi hat geschrieben: Wie funktioniert diese Methode? Was bringt mir der Index? kann ich an einem bestimmten index splitten? wie geht das?
Das sind absolute Basics, die in jedem Tutorial erklärt werden sollten (im offiziellen sind sie es auf jeden Fall ;-) )

Aber weil ich mal lieb bin, zeige ich Dir, wie Du das auch leicht selber hättest rausfinden können (genau dafür nutzt man u.a. Python-Shells!):

Code: Alles auswählen

In [12]: s = "Hallo Welt"

In [13]: s.index("Welt")
Out[13]: 6

In [14]: s[6]
Out[14]: 'W'
flummi hat geschrieben: ich hab mir folgendes gebastelt, diese funktion soll doppelt splitten.
funktioniert allerdings nur für die erste zeile einer hand um die handnummer herauszufinden.
Es wäre schon nett gewesen, das einmal zu demonstrieren. Ich habe mal ein wenig kombiniert und gemutmaßt, dass Du das so getestet hast:

Code: Alles auswählen

In [15]: data = "PokerStars Game #76620334109: Hold'em No Limit ($0.05/$0.10 USD) - 2012/03/04 6:53:25 ET"

In [16]: strfromstr(data, "#", ":")
76620334109
flummi hat geschrieben: ich muss stri.pop (1) solange ausführen solange entweder kein fehler ausgespuckt wird, und falls fehler dann trotzdem mit dem code fortfahren, oder stri.pop (1) solange die liste 2 oder mehr elemente hat.

wie mach ich das jetzt am besten?
Ohne Dir zu nahe treten zu wollen: Am besten gar nicht erst einmal! Dein Code strotzt dermaßen von Anti-Pattern, dass man kaum weiß, wo man anfangen soll! Du solltest alles auf null zurück drehen und erst einmal ein Tutorial durch *arbeiten*. Dann versuche die grundlegenden Sprachelemente zu kapieren und selbständig anwenden zu können. Dieses Parsing ist noch eine Nummer zu hoch für Dich.

Damit Du aber etwas lernst, nehme ich das jetzt mal Schritt für Schritt auseinander... (`data` ist erste Zeile wie oben schon gezeigt)

Code: Alles auswählen

In [22]: res = data.split("#")

In [23]: res
Out[23]: 
['PokerStars Game ',
 "76620334109: Hold'em No Limit ($0.05/$0.10 USD) - 2012/03/04 6:53:25 ET"]

In [24]: res.pop(0)
Out[24]: 'PokerStars Game '
In [22] trennen wir die Zeile am "#" auf und erhalten als Rückgabewert eine Liste mit Strings, wie man in [23] sieht. In [24] schmeißen wir das erste Element raus. So weit so einfach. Aber wozu machst Du das?

Code: Alles auswählen

In [25]: res
Out[25]: ["76620334109: Hold'em No Limit ($0.05/$0.10 USD) - 2012/03/04 6:53:25 ET"]

In [26]: str(res)
Out[26]: '["76620334109: Hold\'em No Limit ($0.05/$0.10 USD) - 2012/03/04 6:53:25 ET"]'
Aha. Du hast nun (mutmaßlich) nur noch ein Element in Deiner Liste. in [26] wandelst Du diese in einen String um. Das ist ziemlicher Murks! Zum einen kommen nun die syntaktischen Zeichen da mit rein `"[]`, zum anderen musst Du beim Format schon sehr genau wissen, dass es nur eine Raute in dieser Zeile gibt. Die Lösung ist also alles andere als robust.

Du willst ja in dem Resultat weiterarbeiten... wieso schnappst Du es Dir nicht direkt aus der Liste nach dem `split`? (Wenn Du bei `pop` einen Index mit dem *falschen* Teil angeben kannst, dann kannst Du doch auch gleich das Element hinter dem *gewünschten* Index rauspicken!?!)

Code: Alles auswählen

In [28]: data.split("#")[1]
Out[28]: "76620334109: Hold'em No Limit ($0.05/$0.10 USD) - 2012/03/04 6:53:25 ET"
Das sieht doch viel einfacher und besser aus, oder?

Danach machst Du den gleichen Fehler noch einmal:

Code: Alles auswählen

In [29]: res = data.split("#")[1]

In [30]: res.split(":")
Out[30]: 
['76620334109',
 " Hold'em No Limit ($0.05/$0.10 USD) - 2012/03/04 6",
 '53',
 '25 ET']
Aha... hier kommen wohl mehrere Doppelpunkte vor. Also haust Du wieder die Liste so lange leer, bis nur noch ein Element vorhanden ist. Wozu das? Das *erste* Element muss doch das gewünschte sein!

Code: Alles auswählen

In [38]: res.split(":")[0]
Out[38]: '76620334109'
Das ist doch viel einfacher, als dann im letzten Schritt bei Dir, noch die syntaktischen Elemente per `strip` rauszuhauen, die man ja eigentlich nur durch die unsinnige Umwandlung der Liste in einen String bekommen hat. Zudem ist es Dir hier egal, wie viele Elemente in der Liste sind. Du willst ja nur das erste...

So und nun kommt's: Man kann das alles zusammenfassen!

Code: Alles auswählen

In [41]: data.split("#")[1].split(":")[0]
Out[41]: '76620334109'
Wow. Aus Deinem elf Zeiler ist ein Zweizeiler geworden...

Ach ja, sinnvoller als das `print` wäre es wohl, das Ergebnis zurückzugeben!

Generell ist diese Lösung aber eher mau. Mittels eines RegExps ließe sich die Nummer viel eleganter und robuster aus dem String holen:

Code: Alles auswählen

In [62]: res = re.search(r"#(?P<hand>\d+):", data)

In [63]: res.groupdict("hand")
Out[63]: {'hand': '76620334109'}
Sicherlich muss man sich in RegExps erst einmal einarbeiten, aber bei dem von Dir gezeigten Format meine ich, dass man damit sicherlich besser fährt, als mit reinen `split`-Operationen. Zumal diese keine reinen Key-Value-Paare liefern, sondern man zumindest im "Value"-Teil das ein oder andere noch zerlegen muss.

Ich denke Du musst auf jeden Fall erst einmal die Basics lernen. Ein simpler Indexzugriff auf SequenceTypes gehört sicherlich dazu ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@flummi: Nach eigener Aussage hast Du bereits „ein paar python bücher gelesen” und Du kennst nicht die absoluten Grundlagen; welche eingebauten Datentypen es gibt und welche grundlegenden Operationen darauf definiert sind‽
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

Ärgerlich, dass anscheinend reines Lesen einem recht wenig beibringt :x
flummi
User
Beiträge: 33
Registriert: Samstag 28. April 2012, 13:33

danke erstmal das hat mein bild abgerundet. ich dachte auch dass das blöd ist alles andere immer rauszuhauen, statt das richtige zu picken, kannte aber die eckigen klammern nicht ;)


res.group () spuckt zwar einen string aus allerdings mit "#" und ":"

Code: Alles auswählen

'#76620334109:'
ich kann jetzt natürlich einfach

Code: Alles auswählen

res.group().strip ("#:")
oder gibts da wieder einen besseren weg?

ich will nämlich die ganzen zahlen später in eine liste spucken, um prüfen zu können ob die hand nicht schon ausgewertet worden ist... und ja das ist vllt ein großer sprung für mich, aber von nichts kommt nichts.

*edit* hat sich erledigt hab grad gelesen dass man auf diese sog. gruppen mit einem argument zugreifen kann. sprich

Code: Alles auswählen

res.group ("hand")
Zuletzt geändert von flummi am Freitag 11. Mai 2012, 17:58, insgesamt 1-mal geändert.
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

Du wirst sehr viele Probleme haben wenn du schon mehrere Bücher gelesen hast, aber in keinem davon weder Index-Zugriffe (Beispiel: a[0]) noch Slicing (Beispiel: a[2:3]) erwähnt wurden. Lerne also bitte die Grundlagen bevor du weiterhin versuchst irgendetwas funktionierendes zusammenzusfrickeln.
Antworten