Yerf!
Eleganz bedeutet manchmal für unterschiedliche Leute unterschiedliche Dinge. Manchmal ist es möglich nah dran am konkreten Ablauf der Dinge dran zu sein wie in Deiner Schleife, manchmal bedeutet es, das eigene Denken im Programmcode wiedergespiegelt zu sehen.
Manchmal ist es auch Betriebsblindheit, dass man nicht merkt, dass man ausgehend von einem einfachen Tool, in das man immer mehr Funktionalität reinsteckt, irgendwann an den Punkt gelangt, wo ein anderer Ansatz als der ursprünglich gewählte wesentlich besser wäre. (Ursprünglich war das Tool nur ein ganz einfacher Syntaxcheck für dieses Fileformat)
• Du hast offenkundig einen Iterator, der Zeilen ausspuckt.
• Für jede dieser Zeilen möchtest Du eine _Liste_ von Mustern ausprobieren.
• Vom ersten Muster aus dieser Liste, das passt, möchtest Du bestimmte _benannte Submuster_ zurück geben.
Was noch fehlt ist eine gewisse Kontextabhängigkeit, sprich ausgehend von früher gefundenen Mustern unterschiedlichn zu reagieren, aber dass lässt sich noch einbauen. (Die gestellte Aufgabe lässt sich grob mit dem Parsen eines JSON-Files vergleichen, nur mit etwas anderer Syntax)
Um das ganze mal umgekehrt aufzubauen: Das erste Stichwort ist „benanntes Submuster“. Man kann ja in Regexps mit (?P<name>...) Gruppen benennen. Das kann man toll nutzen, in Deinem zweiten Regexp z.B. so:
re.compile(r'^\s*Text [(?P<text>\w*)] (?P<content>\w)*\s*{\w*$')
Das Schöne daran ist, dass man aus dem Match-Object mit der Methode m.groupdict() ein Dictionary mit den gefundenen Sub-Mustern herausbekommt.
Ja, das macht das ganze auch später noch gut Verständlich gegenüber den nummerierten Submustern.
Beachte auch das r vor dem Regexp-String. Das zeigt an, dass der String ein sogenannter Rawstring ist, was heisst, dass in diesem String Maskierungen mit dem Backslash nicht interpretiert werden. Man erspart sich dadurch die Verdoppelung der Backslashs; Rawstrings sind also sehr für Regexps beliebt.
Guter Tipp, danke. Soweit bin ich noch nicht in die Documentation von Python vorgedrungen (ich bastel derzeit nur ab und zu ein Hilfsskript damit)
Ich hab hier eine Liste von Zweier-Tupeln, das erste Element ist ein kurzes Label, das zweite das Suchmuster. Das Label ist eigentlich unnötig; ich pack's trotzdem mal rein zur Selbstdokumentation und zum anderen, falls man das Label später noch mal braucht, z.B. als der erkannte Typ der zum Suchmuster passenden Zeile.
Das Label werd ich brauchen um den Kontext (z.B. ob es die Zeile mit der ID oder eine mit zugehörigen Name-Value-Paar) zu ermitteln, von daher ganz gut, dass es vorhanden ist.
Ich verwandel diese Datenstruktur gleich mal daraufhin mit einer list comprehension etwas Praktischeres:
patterns = [(label, re.compile(pattern)) for label, pattern in patterns]
Warum? Kompilierte Regexps sind etwas schneller, also sollte man gleich am Anfang das kompilieren, besonders wenn man sie öfter verwendet. Ist aber nervig zu tippen, deswegen als zweiter, kleinerer Schritt, der die Liste nur in diesem Aspekt verändert bzw. hier neu erstellt. Die Verwendung der Datenstruktur lohnt sich schon allein aus tipp-ökonomischen Gründen. ;)
Performance ist für das Script zwar absolut unwichtig, aber auf die Weise ists natürlich auch recht schnell eingebaut.
Jetzt kommt der spassige Teil, eine Funktion, die eine Zeile Text bekommt, der Reihe nach die Suchmuster drauf anwendet und beim ersten passenden Muster deren gefundene Submuster als Dictionary zurück gibt:
Und das ist jetzt genau der Punkt mit dem wesentlich besseren Ansatz ;-)
Das mir das nicht gleich komisch vorkam mit der ellenlangen Liste an IFs die ich da hatte...
Die Fehlerbehandlung sollte natürlich ausgebaut werden. ;) Ich geb hier wieder ein Tupel mit dem Label zurück, man weiß ja nie, ob man's nicht noch brauchen kann.
Fehlerbehandlung kann recht rudimentär ausfallen, ist nur intern für mich um nicht händisch per Copy&Paste arbeiten zu müssen ;-)
(sprich: das ganze wird eine Art Converter zwischen 2 Formaten, aber wer weis... vielleicht brauch ichs ja für noch mehr)
Der Rest ist klassisch. Man kann es so verwenden ...
~~~python
for line in open("file.txt"):
label, data = first_match(line)
doSomething()
Hier kommt dann für mich noch der Teil mit dem beachten des Kontext und dem Aufbau des verschachtelten Dictionarys das ich am Ende haben will. Sollte aber auch kein großes Problem mehr sein.
> (Für ein anderes, fast gleiches aber schöneres Beispiel siehe [Chapter 17: Dynamic functions](http://diveintopython.org/dynamic_functions/index.html) aus Mark Pilgrims sehr empfehlenswerten freiem Buch „Dive into Python“.)
Werd ich mir mal anschauen.
Danke für die Ausführliche Antwort und die guten Ideen.
Gruß,
Harlequin
PS: grad beim Korrekturlesen von meinem Posting ist mir noch eine Idee gekommen, wie ich meinen ursprünglichen Ansatz hätte lösen können: Da jeweils immer nur ein Suchmuster zutrifft kann ich statt elif-Ketten auch einfach jeden IF-Fall mit einem continue für die äußere Schleife beenden...
Ich werd aber denk ich trotzdem deinen Ansatz aufgreifen, nur für den Fall, dass ich das Tool mit noch mehr Funktionalität ausstatten muss.
--
<!--[if IE]>This page is best viewed with a webbrowser. [Get one today!](http://www.opera.com)<![endif]-->