Kontakt aufnehmen

CGI: Reguläre Ausdrücke

Eine der größten Stärken von Perl liegt in den Verwendungsmöglichkeiten der so genannten regulären Ausdrücke (regular expressions) begründet. Sie sind im Großen und Ganzen genau definierbare und aufgrund der zahlreichen Modifikationsmöglichkeiten ziemlich vielseitig einsetzbare Suchmuster, mit deren Hilfe man bestimmte flexible Inhalte in beispielsweise Zeichenketten finden und durch andere ersetzen kann.

Transliteration - Alternatives Suchen, Ersetzen & Zählen von einzelnen Zeichen

Eins vorweg: Beim Suchen, Ersetzen und Zählen einzelner Zeichen sollte man auf die Anwendung regulärer Ausdrücke verzichten und auf eine für diesen Aufgabenbereich alternative und einfachere Methode, die Transliteration, zurückgreifen.
Hierfür ist die allgemeine Form $String =~ tr/Suchliste/Ersatzliste/[Optionen]; anzuwenden, wobei tr als Transliterationsoperator bezeichnet wird. Ein Zeichen der Suchliste wird dabei - sofern im String vorhanden - durch das entsprechende Zeichen mit gleichem Index aus der Ersatzliste ersetzt:

$String = "abcde";

$String =~ tr/ace/ACE/;
# Ersetzt Kleinbuchstaben a c e durch 
# die entsprechenden Großbuchstaben

$String =~ tr/a-e/A-E/;
# Ersetzt Kleinbuchstaben a b c d e durch
# die entsprechenden Großbuchstaben

Wie im letzten Beispiel zu erkennen, kann man mithilfe des Minuszeichens (-) auch komplette Zeichenbereiche als Such- und Ersatzliste angeben. Während im oberen Beispiel lediglich die Kleinbuchstaben ace durch die jeweiligen Großbuchstaben (ACE) ersetzt werden, erfolgt im zweiten die Ersetzung des gesamten Zeichenbereichs a-e (abcde) durch die entsprechenden Großbuchstaben aus der Ersetzungsliste (Zeichenbereich A-E, also ABCDE).
Da jede Transliteration auch einen Rückgabewert liefert, ist es mit dessen Hilfe auch möglich zu erfahren, ob bzw. wie viele Zeichen während dieses Vorgangs ersetzt wurden. Dies erfolgt bezogen auf das obige Beispiel auf diese Weise:

$String = "abcde";

$Anzahl = ($String =~ tr/ace/ACE/);
#Rückgabewert d. Transliteration in $Anzahl gespeichert

print $Anzahl;
#Gibt Anzahl der ersetzten Zeichen (3) aus

Die Abfrage, ob die gesuchten Zeichen gefunden oder letztendlich ersetzt wurden, könnte über die Abfrage if ($String =~ tr/ace//) {} erfolgen, da die boolesche Bewertung für Zahlen größer 0 (also bei gefundenen Zeichen) true ergibt. Hierbei wird also eine leere Ersatzliste notiert, so dass sich in der Zeichenkette auch keine Änderung vollzieht. An dieser Stelle sollte jedoch der Eleganz wegen die Funktion index() für Zeichenketten eindeutig den Vorzug erhalten.
Notiert man anstelle des Operators =~ den Operator !~, so ist der Rückgabewert der Transliteration umgekehrt. Das bedeutet, dass bei erfolgreicher Suche false und bei erfolgloser Suche dagegen true zurückgegeben wird. Die Abfrage, wie viele Zeichen ersetzt wurden, funktioniert dann logischerweise nicht.
Wie in der allgemeinen Form bereits zu erkennen, kann man für Transliterationen auch Optionen festlegen. Dies wird im entsprechenden Abschnitt näher behandelt.

Suchen und Ersetzen mithilfe regulärer Ausdrücke

Die Struktur für das bloße Suchen mittels regulärer Ausdrücke beruht auf der allgemeinen Form:

$String =~ m/Regulärer Ausdruck/[Optionen];

Bei Verwendung der Schrägstriche / - sie können auch durch andere Buchstaben, Ziffern oder den Unterstrich ersetzt werden - ist die Notation des m optional.
Zur Funktionsweise: Bei dieser Suchmethode wird die Zeichenkette $String von Beginn an nach dem Suchmuster Regulärer Ausdruck durchsucht. Ist die Suche erfolgreich, so bricht sie ab und gibt den Wert true zurück. Des Weiteren wird dann der entsprechende Treffer in der Variable $& gespeichert. Andernfalls ist der Rückgabewert false. Dieser Rückgabewert lässt sich natürlich analog zur Transliteration auch umkehren, indem man anstelle von =~ die Zeichenfolge !~ notiert.
Natürlich kann man die zu suchenden Zeichen bei Auffinden auch ersetzen. Hierfür gilt jedoch eine andere Syntax:

$String =~ s/Regulärer Ausdruck/Ersatzzeichenkette/[Optionen];

Hier wird also anstelle des m ein s und zusätzlich abgegrenzt durch Schrägstriche (oder analog zur Suchsyntax andere Zeichen) eine Ersatzzeichenkette notiert. Das Suchprinzip beruht dabei auf dem obigen, wobei die gefundenen Stellen natürlich zusätzlich ersetzt werden.
Reguläre Ausdrücke können derartig viele unterschiedliche und komplexe Formen annehmen, dass sie für den Laien ziemlich verwirrend und beliebig aussehen mögen. Sie folgen dabei jedoch einem (zugegeben komplexen) strukturierten Aufbau, der im Folgenden schrittweise erläutert werden soll. Hierbei wird sich auch zeigen, warum das Suchen und Ersetzen mithilfe regulärer Ausdrücke für weitaus komplexere Suchmuster vorgesehen und warum das Suchen und Ersetzen einzelner Zeichen mithilfe der Transliteration effizienter zu bewerkstelligen ist.

Einfache reguläre Ausdrücke - Bestimmte Zeichen suchen und ersetzen

Der einfachste Reguläre Ausdruck ist ein bestimmtes Zeichen/eine bestimmte Zeichenfolge, welches/welche in einem String gesucht und anschließend ersetzt werden soll. Wird es/sie gefunden, wird dieser Treffer in der Variable $& gespeichert:

$String = "aceace";

#Suchen nach Zeichenkette "ace":
if($String =~ m/ace/)
{
  print "Zeichenfolge $& gefunden!";
  #Meldung ausgeben, wenn "ace" gefunden
}

#in Zeichenkette ace suchen und ersetzen:
$String =~ s/ace/ACE/; #"ace" durch ACE ersetzen

print $String;  #Gibt Wert von $String, also "ACEace" aus

#oder:

#Suchmuster als Skalar zuweisen:
$regExp = "ace";

$String =~ s/$regExp/ACE/;  #"ace" durch ACE ersetzen

Die Unterschiede zwischen Transliteration und dieser Methode des Suchen und Ersetzens bestimmter Zeichen(folgen) sind anhand dieses Beispiels hervorzuheben: Während bei der Transliteration eine Suchliste übergeben und damit jedes Zeichen dieser Liste durch das entsprechende Zeichen aus der Ersatzliste ersetzt wird, erfolgt bei Anwendung regulärer Ausdrücke die Suche nach einer kompletten Zeichenfolge (regulärer Ausdruck), welche dann durch die Ersatzzeichenkette ersetzt wird. Würde der String $String also z.B. den Wert abcdef besitzen, wäre die obige Suche erfolglos und es käme zu keiner Ersetzung. Des Weiteren wird nach dem ersten erfolgreichen Ersetzen eines Zeichens/einer Zeichenfolge der Vorgang abgebrochen, wenn keine zusätzliche Option angegeben wird, was die letzte Ausgabe erklärt.
Das Suchmuster muss dabei stets genau passen, weshalb dessen Notation besonders bei Verzicht auf Angabe zusätzlicher Optionen gut durchdacht sein sollte. Standardmäßig wird nämlich auch zwischen Groß- und Kleinschreibung unterschieden, so dass die Anweisung $String =~ s/Ace/ACE/; im obigen Beispiel auch keine Ersetzung zur Folge hätte (mehr zum Thema Suchoptionen im Folgekapitel).
Wie im letzten Beispiel zu sehen, kann das Suchmuster auch als Skalar zugewiesen werden. Dies hat den Vorteil, dass beispielsweise in einer Schleife das Suchmuster für wechselnde Anforderungen getauscht werden kann, in dem man vor der Such-/Ersetzungsanweisung den Wert des entsprechenden Skalars ändert.

Möchte man nach wiederholt auftretenden Zeichen bzw. Zeichenketten suchen, muss man nach diesen in geschweiften Klammern ({}) die Länge der zu findenden Zeichenwiederholung notieren. Diese Länge kann auch in einem Zahlenbereich {n1, n2} angegeben werden, wobei Perl stets versucht, die längste gefundene Zeichenwiederholung zu finden:

$String = "aabbbbcc";

#Nach Zeichenwiederholung bb suchen
if($String =~ m/b{2}/)
{
  print "$& gefunden"; #Gibt "bb gefunden" aus
}

#Nach längster Zeichenwiederholung im Bereich 1,3 (b-bbb) suchen
if($String =~ m/b{1,3}/)
{
  print "$& gefunden"; #Gibt "bbb gefunden" aus
}

#Nach längster Wiederholung von ab suchen
if($String =~ m/(ab){1,}/)
{
  print "$& gefunden"; #Gibt "ababab gefunden" aus
}

Wie im letzten Beispiel gezeigt, kann man diesen Zahlenbereich auch offen angeben, so dass Perl die längste Zeichenwiederholung sucht. Des Weiteren demonstriert dieses Beispiel, dass bei Suche nach einer Wiederholung mehrerer Zeichen diese Zeichenfolge eingeklammert notiert werden muss.

Suchoptionen

Der Suchvorgang mit regulären Ausdrücken kann durch Angabe spezieller Optionen beeinflusst werden. Sie werden hinter dem letzten Trennungszeichen (in der Regel Schrägstrich /) notiert. Bei bloßer Suche stehen sie also hinter dem regulären Ausdruck und bei Ersetzungsvorgängen hinter der Ersetzungszeichenkette. Folgende Optionen können in beliebiger Kombination verwendet werden:

Option g ("global"): Bei standardeinstellung (also ohne Angabe dieser Option) wird die Suche nach einem Zeichen oder einer Zeichenkette nach dem ersten zutreffenden Ausdruck abgebrochen. Diese Option unterdrückt dies, so dass alle möglichen Vorkommen des Suchmusters gefunden werden.
Option i ("case-insensitive"): Bei Verwendung dieser Option wird bei der Suche die Groß- und Kleinschreibung ignoriert.
Option s ("single line"): Jede zu durchsuchende Zeichenkette wird bei Angabe dieser Option als eine einzelne Zeichenkette betrachtet, so dass eventuell vorhandene Zeilenvorschübe (Sonderzeichen n) ignoriert werden.
Option m ("multiple lines"): Ermöglicht zusätzlich die Suche auf Zeichenketten, welche aus mehreren Zeilen bestehen, ohne dass auf eine gesonderte Notation acht gegeben werden muss (beispielsweise von Bedeutung bei Anwendung von Ankern (siehe Folgeabschnitt)).
Option x ("extended"): Reguläre Ausdrücke können über mehrere Zeilen hinweg notiert werden, was besonders bei größeren regulären Ausdrücken sinnvoll ist, um so eine bessere Übersichtlichkeit zu erreichen.
Option e ("evaluate"; nur für Ersetzungsvorgänge): Ausdrücke in Ersetzungszeichenketten werden evaluiert (ausgewertet), so dass sie als Perl-Syntax gelten und behandelt werden.
Option c ("compile once"): Wird ein Suchmuster in einem Skalar übergeben, so wird es bei Verwendung dieser Option lediglich einmal mit dessen Wert gesetzt. Sie verhindert also, dass eine Wertänderung des entsprechenden Skalars keine Auswirkung auf das Suchmuster, welches er beschreiben soll, hat. Diese Option sollte nur bei dringender Notwendigkeit verwendet werden.

Anker in regulären Ausdrücken

In regulären Ausdrücken kann man Anker festlegen, welche angeben, an welcher Stelle das gesuchte Zeichen/die gesuchte Zeichenkette auftreten muss, damit es/sie als Treffer erkannt wird. Derartige Anker können beispielsweise am Zeilenbeginn (Notation von ^ am Anfang), am Zeilenende (Notation von $ am Ende), an einer Wortgrenze (Notation von b am Anfang) oder innerhalb eines Wortes (Notation von B am Anfang) des (mehrzeiligen) Strings gesetzt werden:

#Anker an Zeilenbeginn
$String = "ababab";

$String =~ s/^ab/_/g;
#Ersetzt "ab" nur am Zeilenanfang durch Unterstrich
print $String; #Gibt Wert von $String, also "_abab", aus

#Anker an Zeilenende
$String = "ababab";

$String =~ s/ab$/_/g;
#Ersetzt "ab" nur am Zeilenende durch Unterstrich
print $String; #Gibt Wert von $String, also "abab_", aus

#Anker an Wortgrenze
$String = "Das Ist Ein STRING";
$String =~ m/bI/; 
#Findet "I" nur an Wortgrenze ("I" von "Ist")

#Anker innerhalb eines Wortes
$String = "Das Ist Ein STRING";
$String =~ m/BI/;
#Findet "I" nur innerhalb eines Wortes ("I" von "STRING")

Verwendet man die Suchoption m, gibt es zusätzliche Anker für mehrzeilige Strings. A deutet in diesem Fall immer auf den Beginn des gesamten Strings (^ immer Zeilenbeginn!) und Z stets auf das Ende des gesamten Strings ($ immer Zeilenende!).

Zeichenklassen

Durch Notation einzelner Zeichen oder Zeichenbereiche innerhalb eckiger Klammern ([]) kann man Zeichenklassen erzeugen, welche es erlauben, nicht nur nach bestimmten (einzelnen), sondern nach Zeichen dieser (selbst definierten) Klasse zu suchen und ggf. zu ersetzen. Eine derartige Klasse kann beispielsweise die Menge aller Groß- oder Kleinbuchstaben, Ziffern, eine selbst begrenzte Menge (Konsonanten, Vokale, Umlaute oder anders begrenzte Zeichenmengen) oder ähnliches sein:

#selbst begrenzte Klasse [ace]
$String = "abcdefgh";

$String =~ s/[ace]/_/g;
#Zeichen a c e durch Unterstrich ersetzen

print $String;
#Gibt Wert von $String, also "_b_d_fgh" aus


#Klasse aller Groß- bzw. Kleinbuchstaben [a-z] bzw. [A-Z]
$String = "aBcDeFgH";

$String =~ s/[a-z]/_/g;
#Kleinbuchstaben durch Unterstrich ersetzen

print $String;
#Gibt Wert von $String, also "_B_D_F_H" aus

$String =~ s/[A-Z]/-/g;
#Großbuchstaben durch Bindestrich ersetzen

print $String;
#Gibt Wert von $String, also "_-_-_-_-" aus

In Bezug auf Zeichenklassen muss das ^ - Zeichen noch gesondert erwähnt werden, da es in regulären Ausdrücken eine Sonderfunktion besitzt: Wird es am Anfang einer Klasse, d.h. hinter der eröffnenden eckigen Klammer ([) notiert wird, so negiert es die nachfolgende Klasse:

$String = "aBcDeFgH";

$String =~ s/[^A-Z]/_/g;
#gleichbedeutend mit $String =~ s/[a-z]/_/g;

print $String;
#Gibt Wert von $String, also "_B_D_F_H" aus

Auch die Zeichenbereiche lassen sich in Zeichenklassen auf gleiche Weise wie einzelne Zeichen aufzählen:

$String = "aBcDeFgH123";

$String =~ s/[a-z0-9]/_/g;
#Kleinbuchstaben & Ziffern durch Unterstrich ersetzen

print $String;
#Gibt Wert von $String, also "_B_D_F_H___" aus

Einige häufig verwendete Zeichenklassen können auch durch eine verkürzte Form notiert werden. Zu ihnen gehören:

ZeichenklasseVerkürzte NotationPasst auf Zeichenkette mit
[0-9]dZiffern
[^0-9]DGegenstück zu d
[ nrtf]sLeerzeichen oder Steuerzeichen (Zeilenvorschub (newline), Wagenrücklauf, Tabulator, Seitenvorschub)
[^ nrtf]SGegenstück zu s
[a-zA-Z0-9_]weinem Zeichen aus Bereich Buchstaben (Groß- und Kleinschreibung), aus Bereich Ziffern oder Unterstrich
[^a-zA-Z0-9_]WGegenstück zu w

Reguläre Ausdrücke mit Alternativen

Man kann auch mehrere alternative Suchausdrücke deklarieren, indem man sie durch einen Senkrechtstrich (|) voneinander getrennt notiert. Diese Suchschablobe passt auch, wenn nur eines dieser Suchausdrücke gefunden wird. Diese Notation folgt im weiteren Sinne dem Prinzip der Zeichenklassen, nur mit dem Unterschied, dass hier auch Zeichenfolgen aneinandergereiht werden können. Dieser Zusammenhang wird im zweiten Beispiel gezeigt:

#Alternative Suchausdrücke (Zeichenketten)
$String = "Dies ist ein String";

$String =~ s/Das|Der|Dies/Hier/;
#Ersetzt (nur) "Dies" durch "Hier"

print $String;
#Gibt Wert "Hier ist ein String" aus


#Beispiel aus Zeichenklassen mittels Alternativen (Zeichen)
$String = "abcdefgh";

$String =~ s/a|c|e/_/g;
#Zeichen a c e durch Unterstrich ersetzen

print $String;
#Gibt Wert von $String, also "_b_d_fgh" aus

Teilausdrücke des Suchmusters speichern

In einigen Fällen kann es ganz nützlich sein, Teile, welche durch ein Suchmuster gefunden wurden, zu speichern, um sie später noch mal verwenden zu können. Dies ist möglich, wenn man diese Teilausdrücke in runden Klammern () notiert. Die entsprechenden Teile werden in vordefinierte Variablen der allgemeinen Form $n geschrieben, wobei n der Index des gespeicherten Teilausdrucks ist. Der zuerst gespeicherte Substring wird also in die Variable $1 geschrieben, der zweite in $2, usw.:

$String = "Wort1,Wort2";
$String =~ /(w*),(w*)/;

print $1;
#Gibt 1. gespeicherten Teilausdruck ("Wort1") aus

print $2;
#Gibt 2. gespeicherten Teilausdruck ("Wort2") aus

Wenn die Klammern lediglich zur Beeinflussung der Prioritäten (siehe Folgeabschnitt) verwendet werden, d.h. nicht der Speicherung von Teilausdrücken dienen, sollen, muss direkt hinter der öffnenden Rundklammer der reservierte Operator ?: notiert werden:

$String =~ /(?:w*),(?:w*)/;

Sonderzeichen in regulären Ausdrücken

An dieser Stelle sei noch mal eine Übersicht über die Sonderzeichen in regulären Ausdrücken gezeigt. Auch in regulären Ausdrücken müssen die Sonderzeichen, welche sonst Steuerungsfunktionen haben, durch das Voranstellen eines Backslash () maskiert werden. Folgende Sonderzeichen existieren:

SonderzeichenFunktion ohne Maskierung
[]Zeichenklasse
()Beeinflussung der Priorität (Gruppierung) oder Speicherung von Teilausdrücken
{}Wiederholung von bestimmten Zeichen
|Alternativen
+ ? *Operatoren für Wiederholung von
+:beliebig vielen des davor stehenden Zeichens, aber mindestens 1
?:davor stehenden Zeichens, einem anderen oder keinem
*:beliebig vielen des davor stehenden Zeichens oder keins
/häufig Begrenzungszeichen
^Negiert Zeichenklassen oder Operator für Anker an Zeilenbeginn des Strings
ABei Verwendung von Option m Operator für Anker an Stringbeginn
$Operator für Anker an Zeilenende des Strings
ZBei Verwendung von Option m Operator für Anker an Stringende
bOperator für Anker an Wortgrenzen
BOperator für Anker innerhalb von Wörtern
.Beliebiges Zeichen
-Trennungszeichen innerhalb von Zeichenbereichen
nrft usw.Steuerzeichen für Zeilenvorschub, Wagenrücklauf, Seitenvorschub, Tabulator usw.

Prioritäten in regulären Ausdrücken

Hinsichtlich der erläuterten Sonderzeichen gilt für den Perl-Interpreter eine gewisse Rangfolge, welche sich wiederum durch Klammerung (höchste Priorität) beeinflussen lässt:

PrioritätZeichen
hoch


gering
()
+ ? * (Operatoren für Wiederholung)
Zeichen(ketten) ^ A $ Z b B
|

Du arbeitest in einer Agentur oder als Freelancer?
Dann wirf doch mal einen Blick auf unsere Software FeatValue.

Über uns

Stefan Wienströer

Wir entwickeln Webanwendungen mit viel Leidenschaft. Unser Wissen geben wir dabei gerne weiter. Mehr über a coding project

Cookie-Einstellungen

Helfen Sie dabei, uns noch besser zu machen. Wir nutzen Cookies und ähnliche Technologien, um die Website auf Ihre Bedürfnisse anzupassen. Zur Datenschutzerklärung

Auswahl speichern