www.mikrocontroller.net

Forum: PC-Programmierung Python: re Muster


Autor: Daniel -------- (root)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Muster ist wie folgt

abc<NL>
foo : bar<NL>

<NL> ist newline
pattern = re.compile(r'(?P<lhs>.*?)(\s+:\s+(?P<rhs>.*?))?')
m = pattern.match("hallo")
m is not None => True
m.group("lhs") => ''

lhs = left hand side
rhs = right hand side

da die linke Seite alles matchet (.*), darf : nicht konsumiert werden,
daher nongreedy (.*?)
so die rechte Seite ist optional, deswegen steht ihr Inhalt in ()?
da ich jedoch nicht in white spaces interessiert bin, erzeuge ich
neue benannte Gruppe rhs.
Irgendwo habe ich einen Gedankenfehler drin. Kann jemand mir helfen?

edit: ich will also beides matchen können

foo<NL>
foo : bar<NL>

Autor: Klaus T. (gauchi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Heisst nongreedy nicht, dass er abbricht sobald er einen Treffer hat?

(.*) passt auf einen leeren string
der hintere Teil ist wegen dem fehlenden ' : ' einfach leer, das ist 
auch zulässig. Folglich kriegst du '' für lhs zurück.

So glaube ich zumindest, dass das Ergebnis zustande kommt.

Ich würde dein Problem wahrscheinlich eher mit
string.split(' : ')
lösen, aber das erfordert natürlich noch ein paar Zeilen um überzählige 
Leerzeichen zu löschen und fehlende rechte Seiten abzufangen.

Autor: Daniel -------- (root)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
pattern = re.compile(r'^(?P<lhs>.*?)(\s+:\s+(?P<rhs>.*?))?$')

löst das Problem! Hinzugekommen sind nur ^ und $.
Hmm, ^ ist glaube ich irrelevant. $ nicht. Ich verstehe nicht
so wirklich wieso RE-engine $ braucht. Ok, es steht für das
Ende der Zeile. Ende der Zeile ist doch normalerweise \n. (unix)
Oder \r\n (Windows). Vorher habe ich jedoch
pattern = re.compile(r'^(?P<lhs>.*?)(\s+:\s+(?P<rhs>.*?))?', re.DOTALL)
probiert. \n hätte doch in diesem Fall durch . gematched werden müssen.
Hat aber so nicht funktioniert.

Konsumiert $ eigentlich das Newline Zeichen? Im Falle von ^ gibt es
zum Beispiel kein reales Zeichen im Inputstream zu konsumieren.

Autor: Klaus T. (gauchi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das funktioniert, weil die Kombination '^' ... '$' fordert, dass der 
ganze String auf das Muster passt.

Autor: Daniel -------- (root)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danke für den Tipp
vielleicht sollte ich doch sowas lieber nehmen
>
> map(string.strip, "foo : bar".split(":"))
> 

Autor: Daniel -------- (root)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus T. schrieb:
> Das funktioniert, weil die Kombination '^' ... '$' fordert, dass der
> ganze String auf das Muster passt.

ich glaube ich verstehe nicht Punkt für Punkt wie eine RE vorgeht.
Meine naive Annahme ist immer die - RE geht von links nach rechts vor
und match greedy. Wenn wir nongreedy von RE verlangen, dann wird es
tricky. Die RE muss nun schauen was im Pattern(nicht im Matchstring!)
weiter rechts steht. Damit wird das Vertilgen von Zeichen durch .
irgendwann eingestoppt, WENN die rechte Patternseite auf den Rest des
Matchstringes passt. Richtig soweit?
In meinem Fall gibt 2 nongreedy in Folge. Ich glaube mein Fehler war,
dass nach dem 2-ten nongreedy Matchall ich die notwendige rechte Seite
der RE Engine nicht gegeben habe. $ erfüllt genau diese Funktion.
Ich könnte aber ein beliebiges Zeichen benutzen. Beispielsweise

"foox"
"foo : barx"

Entspricht zwar nicht dem was ich matchen will, aber verifiziert
meine Hypothese :)

>>> p = re.compile(r'(?P<one>.*?)(\s+:\s+(?P<two>.*?))?x')
>>> m = p.match("hallo : foox")
>>> m.group("one")
'hallo'
>>> m.group("two")
'foo'
>>> m = p.match("hallox")
>>> m.group("two")
>>> m.group("one")
'hallo'

QED und halliluja :)

Autor: Klaus T. (gauchi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guck Dir mal hier
 http://docs.python.org/library/re.html#regular-exp...
 den *? Operator an, da steht was greedy und nongreedy bedeuten.

Prinzipiell sucht eine Regular Expression so lange, bis jeder Teil des 
Musters seine Entsprechung gefunden hat. Das bedeutet normal aber nicht, 
dass die gesamte Eingabe davon abgedeckt werden muss.

Dein Muster besteht aus zwei Teilen, die jeweils (fast) beliebige Länge 
haben dürfen:
(?P<lhs>.*?)
und
(\s+:\s+(?P<rhs>.*?))?
(Ok, der 2. Teil kann niemals aus einem oder zwei Zeichen bestehen, aber 
Null und >= 3 sind erlaubt.)

Wenn du sie auf non-greedy stellst, wird jedes dieser Muster versuchen, 
einen möglichst kurzen Teil in deiner Eingabe zu finden, so dass das 
Gesamtergebnis passt. Der kürzeste mögliche String, der hier erlaubt 
ist, ist leer.

Durch die '^' und '$' forderst du zusätzlich, dass dein Muster die 
gesamte Eingabe (bzw die ganze Zeile wenn es mehrere sind) abdeckt, also 
muss jedes Zeichen in der Eingabe auch eine Entsprechung im Muster 
finden, also sind 2 Strings der Länge 0 nicht mehr zulässig. Daher 
muss sich deine linke Seite so weit ausdehnen, dass die Rechte Seite 
den Rest übernehmen kann und das kann sie nur wenn ein ' : ' im String 
vorkommt.

Der '^' ist bei Python deshalb nicht notwendig, weil die Funktion match 
immer ab dem Beginn der Eingabe sucht. Das bedeutet, dass du immer ein 
implizites '^' vorne dran hast, wenn du match benutzt.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.