Reguläre Ausdrücke (Regular Expressions / RegEx) mit PHP

Reguläre Ausdrücke (Regular Expressions / RegEx) mit PHP

Mit den PCRE (Perl Compatible Regular Expressions) Funktionen bietet PHP die Möglichkeit vorhandene Strings mit Hilfe eines Patterns zu untersuchen und bei Bedarf zu ersetzen.
Doch was sind Reguläre Ausdrücke überhaupt ? Reguläre Ausdrücke sind Muster (Pattern), mit denen man z.B. überprüfen kann, ob eine Zeichenkette bestimmten Vorgaben, die im Pattern festgelegt werden, entspricht.
Ich kann aus eigener Erfahrung sagen, dass, solange man Reguläre Ausdrücke nicht verstanden hat, man alles versucht um sie zu meiden, da die Pattern teilweise doch recht kryptisch und unverständlich aussehen. Doch wenn man einmal den Durchblick durch das, durchaus logische, System der Regulären Ausdrücke erlangt hat, möchte man sie nicht mehr missen.
Wie aus meinem Einleitungsteil evtl. schon zu erkennen, werde ich in diesem Tutorial zum einen auf den allgemeinen Aufbau der Regex (Regex = Regular Expression = Regulärer Ausdruck) Pattern, sowie auf Backreferences eingehen. Beides werde ich an den beispielhaften Funktionen preg_match() und preg_replace() zeigen und erklären. Auf die weiteren PCRE Funktionen werde ich nicht näher eingehen, da ich denke, dass nachdem man die Grundlagen verstanden hat, sich das erlangte Wissen leicht portieren lässt.
Ein gewöhnliches Muster (Pattern) besteht in PHP aus drei Teilen.
/pattern/i
Delimiter: Das eigentliche Muster wird von sogenannten Delimitern am Anfang und am Ende begrenzt, damit für den Interpreter ersichtlich ist, wo das Muster anfängt und wo es aufhört. Jedes nicht-alphanumerische Zeichen ausser dem \ darf als Delimiter genutzt werden. Es ist also nicht zwingend nötig den / als Delimiter zu nutzen. Oft genutzt werden neben Schrägstrich auch das Prozentzeichen oder das Ausrufezeichen.
Pattern: Dies ist das eigentlich Muster, das im weiteren Verlauf des Tutorials behandelt wird.
Modifier: Nach dem abschließenden Delimiter können sogenannte Modifier angehängt werden, die ebenfalls in einem gesonderten Abschnitt dieses Tutorials behandelt werden.
Damit wir im folgenden einen etwas besseren Bezug zur realen Anwendung haben, führe ich kurz die zwei Funktionen preg_match() und preg_replace() ein.
preg_match()
Betrachtet man sich die PHP-Manual Seite zu preg_match() findet man folgendes vor.
int preg_match ( string pattern, string subject [, array matches [, int flags]])
Für uns sind an dieser Stelle erst mal nur die zwei zwingenden Parameter pattern und subject interessant. Für matches und flags möge man bitte die PHP Seite konsultieren, sie sind für das essenzielle Verständnis von Regulären Ausdrücken nicht zwingend notwending.
Die Funktion erwartet also, dass sie zum einen ein Suchmuster übergeben bekommt (pattern), sowie eine Zeichenkette (subject) auf die sie das Muster anwenden kann.
Als Rückgabewert liefert diese Funktion TRUE bzw. 1 wenn die Suche nach dem Muster erfolgreich war und FALSE bzw. 0 wenn keine Übereinstimmung gefunden wurde.
preg_replace()
Hier sieht die Dokumentation von php.net folgendermaßen aus.
mixed preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit])
Diese Funktion erwartet genau wie auch preg_match ein Suchmuster (pattern) und eine Zeichenkette auf die das ganze angewendet werden soll (subject), jedoch zusätzlich eine Zeichenkette, die an Stelle der gefundenen Bereiche eingesetzt wird (replacement).
Wie man diese Funktion z.B. für die oft besprochenen BB-Tags nutzen kann, erkläre ich am Ende des Tutorials in den Beispielen.
Modifier
Wie schon zu Beginn erwähnt, kann man an den abschließenden Delimiter sogenannte Modifier anhängen, die das gesamte Suchmuster betreffen. So kann man z.B. durch anhängen eine i dafür sorgen, dass die Suche unabhängig von Groß-/Kleinschreibung funktioniert, was z.B. für Suchfunktionen in Datenbanken oder auf Homepages sehr vorteilhaft ist.
Im folgenden eine Liste einiger Modifier und ihrer Funktion.
i
Wie schon erwähnt handelt es sich hierbei um den wohl meistgebrauchten Modifier, da er die Unterscheidung zwischen Groß- und Kleinschreibung deaktiviert.
s
Hängt man den s Modifier an, so interpretiert der Parser den als subject übergebenen Text als eine Zeile. Das heisst, unabhängig von diversen Newline-Metacharakteren (\n) wird der gesamte übergebene Text als eine "Zeile" behandelt. Das s kann man also für single-lined ansetzen.
m
Der m Modifier ist das genaue Gegenstück zum s Modifier und sorgt dafür, dass die übergebene Zeichenkette, als mehrzeilig (multiple-lines) interpretiert wird. Das heisst, dass der Metacharakter ^ jeweils auf den Anfang jeder neuen Zeile zutrifft. Neue Zeilen werden durch ein Newline (\n) eingeleitet.
Ein weiterer interessanter Modifier ist evtl. noch U. U sorgt dafür, dass die
Quantifier (siehe übernächster Abschnitt) nicht „gierig“ sind. Sollte man den Modifier nicht anhängen, so kann es schon mal sein, dass ein Quantifier mehr Zeichen der Zeichenkette betrachtet als eigentlich nötig, da der Parser probiert auf einen möglichst großen Text zu passen.
Ein Beispiel, das z.B. zu Problemen führen könnte:
Code:
$str = "[i ]Hier ist kursiv.[ /i]Hier wiederum nicht.[ i]Hier aber wohl wieder.[ /i]";
// Bitte Leerzeichen in den Italic Tags wegdenken.
Würde man versuchen, aus diesem String folgendes
Code:
<i>Hier ist kursiv.</i>Hier wiederum nicht.<i>Hier aber wohl wieder.</i>
zu machen, so kann es vorkommen, dass wenn man folgendes Muster benutzt
Code:
%\[i\](.*)\[/i\]%
Der * Quantifier gierig wird und uns bei entsprechendem Replacement folgendes ausspuckt:
Code:
<i>Hier ist kursiv.[/i]Hier wiederum nicht.[i]Hier aber wohl wieder</i>
Also wenn ihr vergleichbares realisieren wollt, dann sorgt dafür, dass eure Quantifier nicht gierig werden ;)
Prinzipiell lassen sich Modifier beliebig durch Aneinanderhängen kombinieren. So wäre z.B. folgendes denkbar
/pattern/isU
Auf das Muster würden dann die Modifier i, s und U angewendet.
Metacharaktere
Metacharaktere stehe für bestimmte Teile einer Zeichenkette und erlauben ausserdem mehrere Möglichkeiten für ein Muster zuzulassen. Im folgenden eine Liste der gängisten Metacharaktere und direkt ein paar Beispiele, womit wir die ersten wirklichen Muster stricken.

.
Der Punkt steht für jedes beliebige Zeichen, ausser einem Zeilenumbruch. Wird jedoch der m Modifier angewand, so würde der Punkt auch auf diesen zutreffen.
Beispiel: /./
Dieses Pattern würde auf jede beliebige Zeichenkette passen, die an irgendeiner Stelle irgendein Zeichen hat. Sprich auf alle Zeichenketten, ausser auf eine leere.

^
Der Zirkumflex kennzeichnet den Anfang der Zeichenkette, womit wir auch noch mal näher auf den s und m Modifier eingehen können.
Beispiel: /^Hallo/
Dieses Pattern würde auf jede Zeichenkette zutreffen, die mit einem „Hallo“ beginnt. Hängt man jedoch den s Modifier an
Beispiel: /^Hallo/s
So würde das Muster nur noch zutreffen, wenn jede neue Zeile mit einem „Hallo“ beginnt.

$
Das Dollarzeichen ist das Gegenstück zum ^ und steht für das Ende der Zeichenkette.
Beispiel: /cu$/i
Dieses Pattern würde auf jede Zeichenkette passen, die ein cu, Cu, cU oder CU (wegen dem i Modifier) am Ende jeder Zeile hat. Am Ende jeder Zeile, da hier nicht explizit der m Modifier angegeben wurde. Im Gegensatz dazu würde ein
Beispiel: /cu$/im
auf jede Zeichenkette passen, die insgesamt mit einem cu, Cu, cU oder CU abschließt, und das unabhängig von eventuellen \n in der Zeichenkette.

|
Mit der vertikalen Strich markiert man Alternativen.
Beispiel: /Brief|Paket/
Dieses Muster trifft genau dann zu, wenn die Zeichenkette entweder „Brief“ oder „Paket“ ist.
Beispiel: /^Hallo|cu$/
Dieses Muster hingegen trifft auf alle Zeichenketten zu, die entweder mit „Hallo“ beginnen, oder mit cu aufhören. Hier kommt z.B. cU nicht in Frage, da kein i Modifier verwendet wurde.

()
Die Runden klammern dienen dazu bestimmte Bereiche des Patterns zu gruppieren. Durch die Tatsache, dass sich Klammern beliebig schachteln lassen, bilden sie ein mächtiges Werkzeug. Ausserdem sind sie für die Verwendung von Backreferences wichtig.
Beispiel: /(0,5|1|1,5)kg Paket/
Dieses Muster würde also auf die Zeichenketten „0,5kg Paket“, „1kg Paket“ sowie auf „1,5kg Paket“ passen.
Auch eine Kombination mit beliebigen anderen Metacharakteren ist denkbar, so würde z.B. folgendes Muster
Beispiel: /^(a|b)(x|y)$/
auf alle Zeichenketten passen, die ein a oder ein b am Anfang, sowie ein x oder y am Ende haben. Im konkreten Fall also ax, ay, bx und by.

[]
Die eckigen Klammern benötigt man bei der Verwendung von Charakterklassen, die im übernächsten Kapitel behandelt werden.

{}
Die geschweiften Klammern, werden genutzt, um Zeichenanzahlen anzugeben. Da diese in den Bereich der Quantifier fallen, werden sie im folgenden Kapitel behandelt.
Soll ein Zeichen, welches ein Metacharakter ist, nicht als solcher, sondern als normales Zeichen interpretiert werden, so muss er mit einem vorrangestellten Backslash \ escapet werden.
Ein Muster, dass auf alle Zeichenketten anspricht, die ein (test) anspricht müsste also wie folgt aussehen:
Beispiel: /\(test\)/
Nach diesem Kapitel Metacharaktere sollte auch klar sein, warum die Pattern oft so kryptisch und unverständlich aussehen. Man stelle sich mal ein Pattern mit Alternativen in zwei geschachtelten Ebenen vor, in dem dann noch mit escapeten Sonderzeichen gearbeitet wird ;)

Hier gehts weiter zu Teil 2 meines RegEx-Tutorials: http://www.tutorials.de/resources/regulaere-ausdruecke-teil-2.20/
Autor
Tim C.
Aufrufe
1.304
First release
Last update
Bewertung
0,00 Stern(e) 0 Bewertungen