Python: re Muster

OP #2016761
Muster ist wie folgt

abc<NL>
foo : bar<NL>

<NL> ist newline
1
pattern = re.compile(r'(?P<lhs>.*?)(\s+:\s+(?P<rhs>.*?))?')
2
m = pattern.match("hallo")
3
m is not None => True
4
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>
#2016785
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
1
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.
OP #2016786
1
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
1
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.
OP #2016825
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 :)
#2016906
Guck Dir mal hier
 http://docs.python.org/library/re.html#regular-expression-syntax
 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:
1
(?P<lhs>.*?)
und
1
(\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

Eine eigene Frage? Dieser Thread ist über 15 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.