Inhalt Perl Einführung: Reguläre Ausdrücke |
Bei den regulären Ausdrücken handelt es sich um eine Spezialität von Perl. Reguläre Ausdrücke sind auch sicher einer der Hauptgründe, warum viele Leute, die anfängen Perl zu lernen, es schnell wieder aufgeben. Was sind reguläre Ausdrücke? Reguläre Ausdrücke sind nichts anderes als Muster, mit denen man den Aufbau von Zeichenketten beschreiben kann. Ein regulärer Ausdruck ist also eine Beschreibung, die auf eine ganze Klasse von Zeichenketten paßt. Im Prinzip kennst Du bereits einfache reguläre Ausdrücke, die Du wahrscheinlich ohne zu überlegen angewendet hast, als Du auf der DOS Kommandozeile Befehle wie DIR *.EXE oder DIR SYS* eingeben hast. Das Jokerzeichen * ist hierbei ein Platzhalter für eine beliebige Anzahl beliebiger Zeichen, so daß der erste DOS Befehl soviel heißt wie liste alle Dateien auf, die die Endung EXE haben. Der Zweite DOS Befehl ist etwas einschränkender, er listet alle Dateien und Verzeichnisse auf, die mit der Zeichenkette SYS beginnen, auf die dann eine beliebige Anzahl beliebiger Zeichen folgen kann. Führt man also den Befehl aus, könnte das folgende Listing mit Dateien und Verzeichnissen erscheinen:
SYS.EXE SYSCOM.DOC SYSTEM.SYS SYSSYS.TXT SYSTER.COM SYSTEM SYSTEM32 SYS
Alle diese Datei- und Verzeichnisnamen fangen mit SYS an. Alle anderen Zeichen sind beliebig. Die regulären Ausdrücke, die Du angewendet hast sind also *.EXE und SYS*, die eine allgemeine Klasse von Datei- bzw. Verzeichnisnamen beschreiben. In Perl können reguläre Ausdrücke wesentlich komplexer sein als diese einfachen Beispiele - und sie sind es häufig auch. Bleiben wir bei dem letzten Beispiel für reguläre Ausdrücke in DOS, das SYS* Beispiel. Wie Du Dir sicherlich denken kannst, schreibt man reguläre Ausrücke in Perl etwas anderes. Als erstes stehen alle regulären Ausdrücke in slashes, d.h. //. In unserem Beispiel würden wir also als vorläufige Version /SYS*/ erhalten. Will man in einem regulären Ausdruck andeuten, daß beliebige Zeichen beliebig oft vorkommen dürfen, benutzt man den Punkt, ., und den Stern, *. Der Punkt steht für ein beliebiges Zeichen, der Stern für ein beliebig häufiges Vorkommen des unmittelbar davorstehenden Zeichens. Unser vollständig übersetztes Beispiel lautet also /SYS.*/ . Hier ein weiteres Beispiel, das den Gebrauch des Punktes in regulären Ausrücken vedeutlicht:
/mar.o/
Dieser reguläre Ausdruck paßt auf alle Zeichenketten, die mit mar beginnen, worauf dann ein beliebiges Zeichen folgt und schließlich mit einem o endet. Hier einige Zeichenketten, auf die der reguläre Ausdruck paßt:
marco, marko, margo, marzo.
Zeichenketten, auf die der reguläre Ausdruck nicht paßt:
marcko, marrko
Was passiert nun, wenn die Zeichenkette länger ist? Perl untersucht von links beginnend die Zeichenkette auf Übereinstimmung mit dem regulärem Ausdruck. Wenn eine Übereinstimmung gefunden wird, wird der Vergleich als wahr gewertet. Die folgenden Zeichenketten passen daher auch auf den regulären Ausdruck /mar.o/:
amarco, schmargo, pmarko, ammarkoni, pmarkomar
In den meisten Fällen repräsentieren Zeichen in regulären Ausdrücken sich selbst. Ein a in einem regulärem Ausdruck paßt also auf ein a in einer zu durchsuchenden Zeichenkette, ebenso paßt eine Zeichenfolge dfd3434 in einem regulärem Ausdruck auf ein Vorkommnis der Zeichenkette dfd3434 in der zu durchsuchenden Zeichenkette.
Zeichen, die sich nicht selbst repäsentieren zeigt die folgende vollständige Liste
\ | ( ) [ { ^ $ * + ? .
Diese Zeichen haben Sonderbedeutungen. Die Bedeutung des Punktes haben wir bereits oben erklärt: Ein beliebiges Zeichen. Wir werden jetzt nacheinander die Bedeutung dieser Zeichen diskutieren.
Das Zeichen ^ in einem regulärem Ausdruck steht für den Anfang der Zeile:
/^Henning/ paßt auf folgende Zeichenketten:
Henning Rowlin Henning bla bla
aber nicht auf:
Rowlin, Henning bla bla Henning
Eine einzelne Zeichenkette kann auch mehrere Zeilen beeinhalten, deshalb ist das ^ nicht gleichbedeutend mit Anfang der Zeichenkette. Der reguläre Ausdruck /^Henning/ würde also auch auf den Inhalt der Variablen $var im folgenden Beispiel passen, das Zeichen \n steht hierbei für ein Newline Zeichen (entspricht dem drücken der <RETURN> Taste).
$var = "Hallo\nHenning";
Auf das Zeilenende kann man mit dem $ Zeichen prüfen. /Henning$/ paßt also auf folgende Zeichenketten:
Rowlin, Henning bla bla Henning
Bei folgenden Zeichenketten paßt dies nicht:
Henning Rowlin Henning bla bla
Hierbei ist auch wieder zu beachten, daß sich eine Zeichenkette auch über mehrere Zeilen erstrecken kann. /Henning$/ würde also auch auf den Inhalt der Variablen $var im nächsten Beispiel passen:
$var = "Hallo Henning\nund noch eine Zeile";
Möchte man auf mehrfaches Vorkommen eines Zeichens prüfen gibt es verschiedene Möglichkeiten. Folgt hinter einem Zeichen ein + Zeichen, bedeutet dies mindestens ein Vorkommen des Zeichens in der zu prüfenden Zeichenkette.
/hal+o/ paßt also auf folgende Zeichenfolgen:
hallo halo halllo yxxxhalloxxxx zhallllllllllo hallo
Neben dem + gibt es noch das * als Wiederholungszeichen, hierbei kann das Zeichen vor dem * mehrfach vorkommen, es muß allerdings nicht vorkommen. So paßt /hal*o/ neben den Zeichenketten im letzten Beispiel auch auf:
hao
Will man auf ein null oder einmaliges Vorkommnis eines Zeichens in einer zu untersuchenden Zeichenkette prüfen, verwendet man das ? Zeichen. Der reguläre Ausdruck /pm?.rco/ paßt auf
pmarco parco pmrco
aber nicht auf die Zeichenkette
pmmarco
Man kann auch auf eine exakte Anzahl von Zeichenwiederholungen prüfen sowie eine Mindest- und Höchstanzahl von Zeichenwiederholungen vorgeben. Man benutzt hierzu die geschweiften Klammern {}, die dem betreffenden Zeichen nachgestellt werden.
Damit /ma{2}rco/ paßt müssen in der Zeichenkette genau zwei a vorkommen:
maarco plmaarco xxmaarconi
Damit /ma{2,}rco/ paßt müssen in der Zeichenkette mindestens zwei a vorkommen:
maarco plmaarco xxmaarconi maaarco hallo maaarco
Damit /ma{2,4}rco/ paßt müssen in der Zeichenkette mindestens zwei a vorkommen, aber maximal vier.
Die folgende Tabelle faßt das Gesagte zusammen:
* kein mal oder beliebig oft + mindestens einmal ? einmal oder kein mal {n} genau n-mal {n,} mindestens n-mal {n,m} mindestens n-mal, aber maximal m-mal
Ihr habt euch vielleicht gefragt, wie man die +, * und ? Zeichen auf mehrere Zeichen anwenden kann. Hierzu verwendet man runde Klammern (), mit denen man mehrere Zeichen gruppieren kann.
/(mar)+/ paßt auf marco marmarco mmarco mmarmarco markko
/h(al)*lo/ paßt auf hallo hlo halallo halalallo
/ha(ll)?o/ paßt auf
hallo hao
Eine Liste von Zeichen in eckigen Klammern bietet eine Auswahl aus diesen Zeichen an, auf die der reguläre Ausdruck passen kann. Der Audruck in eckigen Klammern steht nur für ein Zeichen aus der Liste. Das Beispiel /mar[ck]o/ paßt zum Beispiel auf die Zeichenketten
marco marko
aber nicht auf
marcko
Das Beispiel /m[ea][iy]er/ paßt auf
meier meyer maier mayer
Will man eine Auswahl aus einem Ziffernbereich oder einem Bereich des Alphabets treffen, bedient man sich des - Zeichens.
Das Beispiel /[a-z]+/ paßt auf alle Kombinationen aus kleinen Buchstaben, die beliebig oft aber mindestens einmal vorkommen müssen.
/[A-Z][a-z]+/ paßt auf alle Kombinationen aus Buchstaben, die mit einem großen Anfangsbuchstaben beginnen und und von einer beliebgen Anzahl kleiner Buchstaben gefolgt werden.
/[0-9]{5}/ paßt auf alle fünfstelligen Dezimalzahlen.
Mit dem Operatorzeichen | kann man in einem regulärem Ausdruck mehrere alternative Zeichenketten angeben, auf die eine bestimmte Zeichenkette untersucht werden soll.
/^(M|m)arco/ paßt auf alle Zeichenketten, die mit einem großem M ODER einem kleinem m beginnen, worauf die noch die Zeichenkette arco folgt. Das Beispiel paßt also auf:
Marco marco
/(herr|frau) mayer/ paßt also z.B. auf die Zeichenketten
herr mayer frau mayer
Die Besprechung der Sonderzeichen wollen wir an dieser Stelle beenden und uns einer Frage zuwenden, die Ihr euch vielleicht die ganze Zeit über gestellt habt: Was ist, wenn man in einer Zeichenkette z.B. nach einem ? oder einem + sucht? Wendet man diese Zeichen in einem regulärem Ausdruck an, so haben sie spezielle Bedeutungen, wie wir sie bereits weiter oben diskutiert haben. Die Lösung ist ganz einfach, führt jedoch dazu, daß der reguläre Ausdruck nicht mehr ganz so gut lesbar ist: Man stellt dem Sonderzeichen einfach ein \ voran. Stellt euch vor ihr sucht in einem Text entweder nach der email Adresse marco@tekromancer.com oder henning@tekromancer.com. Das Problem ist einzig der Punkt, der sonst die Bedeutung "beliebiges Zeichen" hat und hier sich selbst repräsentieren soll. Hier ist die Lösung:
/(marco|henning)@tekromancer\.com/ paßt also auf
marco@tekromancer.com henning@tekromancer.com
Buchstaben denen ein Backslash vorangestellt wird, kennzeichnen Sonderzeichen oder bestimmte Zeichenklassen. Hier eine (fast) vollständige Liste:
\t paßt auf einen Tabulator \r paßt auf ein Carriage Return \f paßt auf einen Formfeed \d paßt auf eine Ziffer \D paßt auf alle Zeichen außer Ziffern \w Wortzeichen, also alle Zeichen von a bis z (in Groß- und Kleinschrift), Ziffern (0-9) und den Unterstrich _
Stelle Dir vor, Du suchst beliebige Wörter mindestens der Länge 5, dann könntest Du folgendes schreiben:
/\w{5,}/ paßt auf
marco xyzab s_ddh 12mar 1_2_3
\W Kein Wortzeichen \s paßt auf Leerzeichen, Tabulator, Newline, Carriage Return, Formfeed \S paßt auf auf alles außer Leerzeichen, Tabulator, Newline, Carriage Return, Formfeed \A paßt auf den Anfang einer Zeichenkette \Z paßt auf das Ende der Zeichenkette \b paßt auf eine Wortgrenze z.B. paßt /marco\b/ auf adjsdakmarco hallo marco
aber nicht auf
marcoxxxx jhgjhgjhmarco4554535
Ferner paßt /\bmarco\b/ auf
marco @marco% (@ und % sind KEINE Wortzeichen, siehe obige Definition von \w) &marco? (& und ? sind KEINE Wortzeichen, siehe obige Definition von \w)
aber NICHT auf
3243243marco marcofasdfad 23423marco32432423
Wie führt man nun eine Suche durch, die nicht auf Groß- und Keinschrift achtet? Hierzu kann man einen Modifikator verwenden, Modifikatoren werden einfach an den regulären Ausdruck gehängt.
/marco/ paßt, wie ihr bereits wißt, auf alle Zeichenketten, die marco enthalten, also auf
marco dsfasdfmarcokjkljl 323223marco213123 dsfadsmarco
/marco/ paßt aber nicht auf
MARCO 3214324MARCO MArco
Wenn man bei der Suche nach marco die Groß- und Kleinschreibung ignorieren will, muß man folgendes tun
/marco/i
Das i steht für ignore (=ignorieren) und bezieht sich auf die Groß- und Kleinschreibung. Es gibt noch weitere Modifikatoren, auf die werden wir hier aber nicht näher eingehen.
Perl Einführung: Reguläre Ausdrücke Inhalt |