PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Hilfe bei einem regulären Ausdruck (PCRE)


Roi Danton
2009-04-19, 12:15:38
Folgendes soll aus einem Text gefiltert werden:
Lorem ipsum dolor sit amet, consectetuer sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero [#232,nid,linktext="eigener Text mit vielen 8-bit Zeichen" Kommentar] eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus [#view_molecular,viewdisplay=page_1 Kommentar] est Lorem ipsum dolor sit amet [#8,tid Kommentar]. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr [#view_atomic,viewargs="Si&O" Kommentar]asd], sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat [#2098, Kommentar], sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.Alle werden mit drei Backreferences ausgelesen (Zahl/Text/ID, Optionen mit Komma getrennt, Kommentar). Das (für mich) Schwierige ist der Tag mit linktext="viele Zeichen erlaubt". Der Ausdruck für diese Tags ist:
\[#([0-9a-zA-Z_]+),((?:[0-9a-zA-Z=,]*(?:"[^"\r\n]*")*)*) ([^\]\r\n]+)\]Für die einzelnen Tags funktionierts, allerdings nicht für alle Tags zusammen (die Tags werden vom Filter nicht umgewandelt und auch nicht mehr angezeigt, leider ohne sichtbare Ausgabe von PHP Fehlern). Ich vermute, dass in der Regex ein Bug drin ist. Wahrscheinlich ist für die mittlere Backreference ein anderer Ansatz nötig:((?:[0-9a-zA-Z=,]*(?:"[^"\r\n]*")*)*)Sowohl
nid,nolink,translation=en
tid
linktext="äußerst süßes Öl",viewid
(kein Zeichen)sollen erfasst werden. Das Leerzeichen darf nur innerhalb der Anführungszeichen stehen, da der Kommentar von den Optionen durchs Leerzeichen getrennt wird.

Hat jemand einen sinnvolleren Ausdruck im Kopf?

Monger
2009-04-19, 12:20:13
Hm, ich versteh das Problem. Kannst du dir sicher sein, dass innerhalb deiner "Kommentare" keine weiteren eckigen Klammern vorkommen? Dann würde ich meine Regex Lazy machen:

\[#.+?\]

Dann versucht er halt immer die kleinste denkbare Klammer mit nem Lattenzaun als erstes Zeichen zu kriegen. Scheint mir aber in deinem Fall am sinnvollsten zu sein.

Wenn du die Klammern erstmal hast, kannst du den Inhalt nochmal in einer zweiten Stufe auseinander nehmen. Manchmal ist es besser, nicht alles in einen einzigen regulären Ausdruck zu stopfen.

Monger
2009-04-19, 12:30:37
Nachtrag: das innerhalb der Klammern scheint mir doch etwas von folgender Bauart zu sein:

\w+(,\w+(?:=".+")?)*\s\w+

Also: erstes \w+ ist halt irgendeine Folge (da müssen wahrscheinlich noch andere Zeichen wie Unterstriche o.ä. dazu), die große Klammer bedeutet dann "irgendein Text nach einem Komma, mit einem optionalen Anteil mit "Ist gleich irgendwas mit Anführungszeichen") und hinten dann ein Leerzeichen und der Kommentar.

Roi Danton
2009-04-19, 13:41:38
Danke für die Antworten. Die Variante .+? verwende ich nicht so gern, da dann die regex Engine bei längeren Strings unnötig viele Schritte braucht. Wenn ich Code lese, kann ich mit 0-9a-zA-Z_ mehr anfangen als mit \w (Gewohnheit ;) ).

Btw, Ursache gefunden, sie lag nicht in der einen Regex selbst.

Ich habe weitere Ausdrücke gehabt, um Tags ohne Kommentar zu erfassen.

// ID with options, alphanumeric for viewname.
'@\[#([0-9a-zA-Z_]+),((?:[,0-9a-zA-Z=]*(?:"[^"\r\n]*")*)*)\]@e' => '_linodef_filter_processoptions($1,False,0,"$2");',
'@\[#([0-9]+):([0-9a-z_]+),((?:[,0-9a-zA-Z=]*(?:"[^"\r\n]*")*)*)\]@e' => '_linodef_filter_processoptions($1,$2,0,"$3");',
'@\[#([0-9]+):([0-9a-z_]+):([0-9]+),((?:[,0-9a-zA-Z=]*(?:"[^"\r\n]*")*)*)\]@e' => '_linodef_filter_processoptions($1,$2,$3,"$4");',

// ID with options, alphanumeric for viewname, comment has to be substituted too.
'@\[#([0-9a-zA-Z_]+),((?:[,0-9a-zA-Z=]*(?:"[^"\r\n]*")*)*) ([^\]\r\n]+)\]@e' => '_linodef_filter_processoptions($1,False,0,"$2");',
'@\[#([0-9]+):([0-9a-z_]+),((?:[,0-9a-zA-Z=]*(?:"[^"\r\n]*")*)*) ([^\]\r\n]+)\]@e' => '_linodef_filter_processoptions($1,$2,0,"$3");',
'@\[#([0-9]+):([0-9a-z_]+):([0-9]+),((?:[,0-9a-zA-Z=]*(?:"[^"\r\n]*")*)*) ([^\]\r\n]+)\]@e' => '_linodef_filter_processoptions($1,$2,$3,"$4");',

Dieser Ausdruck ...
\[#([0-9a-zA-Z_]+),((?:[,0-9a-zA-Z=]*(?:"[^"\r\n]*")*)*)\]... angewendet z.B. auf [#232,nid,linktext="eigener Text mit vielen 8-bit Zeichen" Kommentar] erzeugt eine Schrittanzahl für die regex Engine von mehreren 100k Schritten. Bei dieser Zahl bricht die Regex Engine ab, deshalb kam kein Ergebnis raus (leider auch kein PHP Fehler).

Die Trennung war dumm und den Wert für den Kommentar brauche ich nicht. So lautet ein funktionierender Ausdruck so:
\[#([0-9a-zA-Z_]+),((?:[,0-9a-zA-Z=]*(?:"[^"\r\n]*")*)*)[^\]\r\n]*\]

Ideal wärs noch, wenn ich vorher sowas linktext="Lorem ipsum dolor sit amet, consectetuer sadipscing elitr",nid in so etwas linktext="Lorem ipsum dolor sit amet\xf4\x80\x81\x8c consectetuer sadipscing elitr",nid umwandeln könnte, also Kommata innerhalb von "" ersetzen.