Felix Riesterer: Regulärer Ausdruck für Links

Beitrag lesen

Lieber RuD,

[^?]+)
                        // also NICHT ein oder mehrere Fragezeichen, wieso ist das nicht escaped?

In einer Character Class haben nur noch zwei Zeichen besondere Bedeutung: die schließende eckige Klammer (sie schließt die Character Class wieder) und das Zirkumflex (es negiert die CC). Der Punkt ist nur noch ein Punkt, eine Klammer ist nur noch eine Klammer (und keine Parenthese mehr), ein Sternchen ist nur noch ein Sternchen usw.

(?:?([^"]+))?"~', // Und hier ist alles zu spät

Hier will ich mal von innen anfangen:
  [^"]+                 // wie oben: NICHT ein oder mehrere " (?)

Nein! So viele nicht-"-Zeichen wie möglich.

?                    // davor ein Fragezeichen

Stimmt.

das ? am Ende         // macht das ganze zur später wieder einzufügenden "Varbiable"

Nein, es bedeutet, dass die komplette Parenthese auch komplett entfallen darf, damit der Ausdruck trotzdem noch matcht (für Links ohne Search-String).

(?:...)               // ich habs noch nicht geschnallt
                        // was genau wird vergessen

Alles darin!

Beispiel:

preg_match('~(abc)def(?:ghij)?~', 'abcdefxyz') // true, \\1=abc \\2 existiert nicht wegen ?:  
preg_match('~(abc)def(?:ghij)?~', '_abcdefghijxyz') // true, \\1=abc \\2 existiert nicht

Den Inhalt der ersten Parenthese (Klammernpaar) kann ich per \1 wieder referenzieren, den Inhalt der zweiten Parenthese kann ich _nicht_ referenzieren, da sie "vergessen" wird.

denn sonst stünde im Ersetzungsstring später ein "\1" und ein "\3", aber kein "\2" - klar?
Nicht wirklich .-(

Beispiel:

preg_match('a(bc)d(ef(gh))?', 'xabcdefghuvw') // true, \\1=bc, \\2=efgh \\3=gh  
preg_match('a(bc)d(?:ef(gh))?', 'xabcdefghuvw') // true, \\1=bc, \\2=gh \\3 existiert nicht  
preg_match('a(bc)d(?:ef(gh))?', 'xabcduvw') // true, \\1=bc, \\2= \\3 existiert nicht

Jetzt zu unserem Fall:
$tpl_source = preg_replace('~(<a href=".*[^?]+)(?:\?([^"]+))?"~', '\\1?\\2&amp;'.SID, $tpl_source);

Im Ersetzungsstring wollte ich kein \3 verwenden. Aber es hätte auch so funktionieren sollen:
$tpl_source = preg_replace('~(<a href=".*[^?]+)(\?([^"]+))?"~', '\\1?\\3&amp;'.SID, $tpl_source);

Ich ignoriere einfach, dass da noch eine weitere Parenthese (\2) gefunden wurde, daher steht jetzt in meinem Ersetzungsstring "\1\3". Ob ich meinen Code später in ein paar Monaten aber überhaupt noch verstehe... Da denke ich, dass es leichter fällt, wenn da "\1\2" steht.

Außerdem braucht PHP dann weniger Resourcen; es ist sparsamer. Bei komplexeren RegExen kann das schon zu spürbaren Performance-Verlusten führen, wenn man unbenötigte Parenthesen trotzdem "merken" lässt.

Jetzt will ich als erstes ein echtes Fragezeichen haben. Das ist aber mit einer Sonderbedeutung belegt. Deshalb muss ich für ein echtes Fragezeichen dieses mittels Backslash escapen. Daher steht hier ?, klar?
In der Klammer will ich alle Zeichen, die keine doppelten Anführungszeichen sind, also wieder eine negierte Character Class. Im Klartext will ich also alles zwischen (?) und ("), nämlich den Search-String. Klar soweit?
Teils teils....

preg_match('~ab?~', '_acde') // true, denn b soll keinmal oder einmal vorkommen  
preg_match('~ab?~', '_abcde') // true  
  
preg_match('~(gute)? miene~', 'er machte gute miene zum bösen spiel') // true, \\1=gute  
preg_match('~(gute)? miene~', 'er machte keine miene zum bösen spiel') // true, \\1=

http://www.regular-expressions.info
Schöne Seite, sehr ausführlich aber ENGLISH, gibt es eine eben so gute deutsch Seite!

Also ich kenne keine (brauche auch keine)... Aber was stört Dich am Englischen?

Liebe Grüße aus Ellwangen,

Felix Riesterer.