Reguläre Ausdrücke sind genau definierte Suchmuster. Mit Hilfe dieser Suchmuster können Sie beispielsweise Variableninhalte durchsuchen und bestimmte Inhalte daraus herausziehen oder ersetzen. So können Sie mit Hilfe von regulären Ausdrücken etwa beim Einlesen von Dateien (z.B. einer Datei mit Einträgen eines Gästebuchs) anhand der Konventionen, nach denen die Datei aufgebaut ist, die einzelnen Einträge geordnet einlesen und als HTML-Code an den aufrufenden Browser übertragen lassen. Reguläre Ausdrücke sind auch ein mächtiges Mittel, um große Datenbestände nach komplexen Suchausdrücken zu durchforsten.
Reguläre Ausdrücke sind allerdings für Neulinge, die nicht aus der Unix-Welt kommen, sehr ungewohnt und der Hauptgrund dafür, warum in manchen Perl-Scripts ziemlich merkwürdige, kryptisch anmutende Zeichenfolgen vorkommen. Wer allerdings mit dem Unix-Befehl grep
vertraut ist, kommt auch mit den regulären Ausdrücken in Perl zurecht.
Zwei kleine einführende Beispiele sollen zeigen, in welchen Situationen reguläre Ausdrücke typischerweise zum Einsatz kommen.
Anzeigebeispiel: So sieht's aus (Zum Aufruf des Scripts ist eine Internet-Verbindung erforderlich)
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title>\n"; print "</head><body>\n"; my @Orte = ("Madrid","London","Mailand","Paris","Rom","München"); foreach(@Orte) { if( $_ =~ /^M/ ) { print "$_ fängt mit M an<br>\n"; } } print "</body></html>\n";
Das Beispiel deklariert einen Array namens @Orte
mit sechs Städtenamen. Dann geht es die Einträge des Arrays mit einer foreach-Schleife der Reihe nach durch. Im Schleifenblock wird überprüft, ob der Städtename im aktuellen Schleifendurchlauf mit M anfängt. Dazu wird die vordefinierte Variablen $_
, in der ja in einer foreach
-Schleife der aktuelle Wert enthalten ist, mit dem Operator =~
an einen regulären Ausdruck gebunden. Der Operator =~
ist speziell für reguläre Ausdrücke gedacht. Der reguläre Ausdruck selbst steht per Voreinstellung in Schrägstrichen. Innerhalb der Schrägstriche wird ein Suchmuster definiert. Das Suchmuster ^M
im Beispiel bedeutet so viel wie "fängt mit M an".
Die ganze Anweisung if( $_ =~ /^M/ )
ist also so zu lesen: wenn die Bedingung erfüllt ist, dass der Wert des aktuellen Schleifeninhalts mit einem M anfängt ...
Genaugenommen können Sie die Zeichenfolge $_ =~
auch weglassen, da der reguläre Ausdruck dann automatisch an die vordefinierte Variable $_
gebunden wird. Um eine bessere Verständlichkeit zu erhalten, wurde hier die ausführliche Notation gewählt.
Das Beispiel gibt in diesem Fall den Schleifeninhalt aus. Am Ende werden also aus dem Array @Orte
die drei Städte ausgegeben, die mit M beginnen.
Das folgende Beispiel ist etwas anspruchsvoller:
Anzeigebeispiel: So sieht's aus (Zum Aufruf des Scripts ist eine Internet-Verbindung erforderlich)
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title>\n"; print "</head><body>\n"; my $Zeile = "{link:http://de.selfhtml.org/{SELFHTML-Seiten}}"; $Zeile =~ /\{link:(.*)\{(.*)\}\}/; my $Link = $1; my $Linktext = $2; print "<a href=\"$Link\">$Linktext</a>"; print "</body></html>\n";
In diesem Script gibt es einen Skalar namens $Zeile
, der als Wert eine Zeichenkette speichert, die offensichtlich eine bestimmte Struktur hat. Sie steht in geschweiften Klammern. Zuerst ist link:
notiert, dann folgt ein URI, und dann folgt, nochmals in geschweifte Klammern gesetzt, ein Text. Diese Struktur mit den geschweiften Klammern ist jetzt frei erfunden. Doch fast die gesamte EDV besteht daraus, Daten nach irgendwelchen für Computer wiedererkennbaren Strukturen oder Konventionen zu speichern. Reguläre Ausdrücke sind dafür geeignet, aus solchen Strukturen etwas Bestimmtes herauszufiltern. Im Beispiel filtert das Script mit Hilfe eines regulären Ausdrucks aus der Zeichenkette den URI und den Text in der zweiten, inneren geschweiften Klammer heraus und bastelt aus diesen beiden Teilwerten einen HTML-Verweis, den es am Ende mit print
ausgibt.
Mit der Anweisung $Zeile =~ /\{link:(.*)\{(.*)\}\}/;
wird der reguläre Ausdruck, der zwischen den beiden Schrägstrichen steht, auf den Wert des Skalars $Zeile
angewendet. Um die fürchterliche Ansammlung von Zeichen erst einmal etwas zu entwirren, seien zunächst die Backslashes \
darin erwähnt. Diese dienen zur Maskierung des jeweils nachfolgenden Zeichens und bedeuten einfach nur: das nächste Zeichen soll als das Zeichen behandelt werden, das da steht. Also \{
heißt beispielsweise einfach nur: das folgende Zeichen {
bitte nicht anders interpretieren als es da steht.
Das, worauf der reguläre Ausdruck passen soll, soll also demnach mit der Zeichenfolge {link:
anfangen. Danach kann erst mal kommen was will. Ausgedrückt wird dies durch .*
Irgendwann soll dann noch einmal eine öffnende geschweifte Klammer {
in dem durchsuchten Wert vorkommen. Dahinter kann wieder kommen was will, also .*
, und am Ende sollen nochmals zwei schließende geschweifte Klammern vorkommen. So wird also ein "Muster" mit Hilfe des regulären Ausdrucks definiert, das auf den untersuchten Wert passt, aber einige Dinge variabel lässt.
Auch hier wurde der Verständlichkeit halber eine Vereinfachung gewählt. Der Teilausdruck .*
funktioniert zwar bei diesem Beispiel, kann jedoch in ungünstigen Fällen aufgrund seiner Gierigkeit zuviel erkennen.
Die beiden variablen Bereiche, also jene, die durch .*
markiert sind, werden im Beispiel jeweils in runde Klammern eingeschlossen. Die runden Klammern zeigen den Wunsch an, dass Perl sich das, was zwischen diesen Klammern steht, merken soll. Im Beispiel merkt es sich auf diese Weise zwei variable Bereiche:
{link:
http://www.selfhtml.org/{
SELFHTML-Seiten}}
Die fett dargestellten Bereiche sind nun in den beiden Klammern gespeichert.
Um an die gespeicherten Werte heranzukommen, stellt Perl vordefinierte Variablen namens $1
, $2
, $3
usw. zur Verfügung. In $1
ist der Inhalt der ersten runden Klammer im regulären Ausdruck gespeichert, in $2
der Inhalt der zweiten runden Klammer. Das Beispiel-Script deklariert zwei Skalare namens $Link
und $Linktext
, denen es die beiden in den runden Klammern gespeicherten Werte zuweist.
Der Rest ist dann nicht mehr schwer: in einer print
-Anweisung, die den Code für einen HTML-Verweis ausgibt, werden die beiden Skalare $Link
und $Linktext
an den Stellen eingefügt, wo ihre Werte hingehören.
Ein wichtiger Anwendungsbereich für reguläre Ausdrücke ist auch das Suchen und Ersetzen mit regulären Ausdrücken. Reguläre Ausdrücke können ferner in einigen Perl-Funktionen als zu übergebende Parameter vorkommen, beispielsweise in der Funktion split.
Sie können in einer Zeichenkette
Solche Ausdrücke eignen sich weniger zur Mustererkennung als dazu, herauszufinden, ob in einem Wert bestimmte Zeichen, z.B. unerlaubte Zeichen, vorkommen.
Nr. | Regulärer Ausdruck (Beispiel) | passt auf eine Zeichenkette, die (mindestens) |
---|---|---|
1. | /a/ |
ein 'a' enthält |
2. | /[ab]/ |
ein 'a' oder ein 'b' enthält |
3. | /[A-Z]/ |
einen Großbuchstaben enthält (passt nicht auf Umlaute) |
4. | /[0-9]/ |
eine Ziffer enthält |
5. | /\d/ |
eine Ziffer enthält - genau wie (4.) |
6. | /\D/ |
ein Zeichen enthält, das keine Ziffer ist |
7. | /[-\d]/ |
eine Ziffer oder ein Minuszeichen enthält |
8. | /[\[\]]/ |
eine eckige Klammer enthält |
9. | /[a-zA-Z0-9_]/ |
eins der Zeichen vom Typ Buchstabe (ohne Umlaute), vom Typ Ziffer oder einen Unterstrich enthält |
10. | /\w/ |
eins der Zeichen vom Typ Buchstabe, vom Typ Ziffer oder einen Unterstrich enthält - (fast) genau wie (9.); ob Umlaute erkannt werden können, hängt von der Systemkonfiguration ab |
11. | /\W/ |
ein Zeichen enthält, was weder Buchstabe noch Ziffer noch Unterstrich ist; ob Umlaute ausgeschlossen werden können, hängt von der Systemkonfiguration ab |
12. | /\r/ |
ein Steuerzeichen für den Wagenrücklauf enthält |
13. | /\n/ |
ein Steuerzeichen für den Zeilenvorschub enthält |
14. | /\t/ |
ein Steuerzeichen für den Tabulator enthält |
15. | /\f/ |
ein Steuerzeichen für den Seitenvorschub enthält |
16. | /\s/ |
ein Leerzeichen oder ein Steuerzeichen aus (12.-15.) enthält |
17. | /\S/ |
ein Zeichen enthält, das kein Leerzeichen oder Steuerzeichen aus (12.-15.) ist |
18. | /[^äöüÄÖÜ]/ |
ein Zeichen enthält, was kein deutscher Umlaut (in der entsprechenden Zeichenkodierung) ist |
19. | /[^a-zA-Z]/ |
ein Zeichen enthält, welches kein Buchstabe ist (ohne Umlaute) |
Wenn Sie mit einem regulären Ausdruck prüfen wollen, ob in einer Zeichenkette ein bestimmtes Zeichen vorkommt, genügt es, dieses Zeichen innerhalb der Begrenzer (hier: der Schrägstriche) zu notieren, so wie in den Beispielen (1.) und (12.-15.). Wenn das gesuchte Zeichen innerhalb von regulären Ausdrücken ein reserviertes Zeichen ist, wie beispielsweise ein +
, müssen Sie es mit einem umgekehrten Schrägstrich maskieren (\+
). Reservierte Zeichen sind auf jeden Fall +?.*^$()[]{}|\
.
Wenn Sie allerdings wirklich nur das Vorkommen eines festen Zeichens oder einer festen Zeichenkette überprüfen wollen, ist die Funktion index die bessere Wahl.
Für reguläre Ausdrücke interessanter sind Fälle, in denen Sie prüfen wollen, ob ein Zeichen vorkommt, das auf verschiedene Möglichkeiten passen soll, oder explizit nicht passen soll, wie in den Beispielen (2.-11.) und (16.-19.). Dafür gibt es innerhalb der regulären Ausdrücke die so genannten Zeichenklassen. Eine Zeichenklasse wird grundsätzlich innerhalb eckiger Klammern [...]
notiert, wie in den Beispielen (2.-4.), (7.-9.) und (18.-19.). Eine Zeichenklasse passt immer genau auf ein Zeichen. Innerhalb dieser Zeichenklasse können Sie nun die verschiedenen Zeichen dieser Klasse aufzählen, indem Sie die Zeichen nacheinander notieren. Reservierte Zeichen müssen auch hierbei explizit mit einem umgekehrten Schrägstrich maskiert werden, wie in Beispiel (8.). Wenn Sie einen größeren Zeichenbereich haben, der passen soll, können Sie diesen angeben, indem Sie das erste Zeichen des Bereichs notieren, danach ein Minuszeichen als Bindestrich -
und danach das letzte Zeichen des Bereichs, wie in den Beispielen (3.), (4.), (9.) und (19.). Wenn Sie den Bindestrich als wirkliches Zeichen meinen, notieren Sie ihn am Anfang der Zeichenklasse, wie in Beispiel (7.).
Für bestimmte häufig vorkommende Zeichenklassen gibt es Abkürzungen. So entspricht [0-9]
\d
und [ \r\n\t\f]
entspricht \s
. [a-zA-Z0-9_]
entspricht im allgemeinen der Abkürzung \w
. Sie können diese Abkürzungen auch innerhalb von Zeichenklassen verwenden, wie in Beispiel (7.).
Sie können Zeichenklassen negieren, um festzulegen, dass sie auf ein bestimmtes Zeichen nicht passen sollen, wie in den Beispielen (18.) und (19.). Dazu notieren Sie direkt nach der öffnenden eckigen Klammer [
das Hütchensymbol ^
. Beachten Sie, dass auch dann mindestens ein Zeichen in der durchsuchten Zeichenkette vorhanden sein muss, auf das der reguläre Ausdruck nicht passt, obwohl kein Buchstabe in der Zeichenkette vorkommt. Wenn Sie also Beispiel (19.) auf eine leere Zeichenkette anwenden, bekommen Sie als Ergebnis, dass der reguläre Ausdruck nicht passt. Um abgekürzte Zeichenklassen wie etwa \s
oder \d
zu negieren, ändern Sie einfach den "Namen" der Abkürzung in einen Großbuchstaben, also \S
oder \D
.
Sie können
Diese Art von regulären Ausdrücken ist dazu gedacht, um etwa in einem Wert nach dem Vorkommen eines bestimmten Wortes, einer beliebigen Teilzeichenkette oder nach einem Muster zu suchen.
Nr. | Regulärer Ausdruck (Beispiel) | Wirkung |
---|---|---|
1. | /aus/ |
passt auf 'aus' - auch in 'Haus' oder 'Mausi' |
2. | /aus?/ |
passt auf 'aus' usw. - aber auch 'au' und 'auf' |
3. | /a./ |
passt auf 'ab' und 'an' (ein beliebiges Zeichen hinter 'a', außer \n ) |
4. | /a+/ |
passt auf 'a' und 'aa' und 'aaaaa' (ein oder beliebig viele 'a') |
5. | /a*/ |
passt auf 'a' und 'aa' und 'aaaaa' und 'b' (kein oder beliebig viele 'a') |
6. | /Ha.s/ |
passt auf 'Haus' und 'Hans' aber nicht 'Hannes' |
7. | /Ha.+s/ |
passt auf 'Haus' und 'Hans' und 'Hannes' (ein oder beliebig viele beliebige Zeichen, außer \n ) |
8. | /Ha.*s/ |
passt auf 'Haus' und 'Hans' und 'Hannes' (kein oder beliebig viele beliebige Zeichen, außer \n ) |
9. | /Ha.?s/ |
passt auf 'Haus' und 'Hans' und 'Hase' |
10. | /x{10,20}/ |
passt auf zwischen 10 und 20 'x' in Folge |
11. | /x{10,}/ |
passt auf 10 und mehr 'x' in Folge |
12. | /x.{2}y/ |
passt auf 'xxxy' oder 'xaby' usw. (zwei beliebige Zeichen zwischen 'x' und 'y', außer \n ) |
13. | /Hans\b/ |
passt auf 'Hans' aber nicht 'Hansel' (Wortgrenze) |
14. | /\baus/ |
passt auf 'aus' oder 'außen' aber nicht 'Haus' (Wortgrenze) |
15. | /\baus\b/ |
passt auf 'aus' aber nicht 'Haus' und auch nicht 'außen' (Wortgrenze) |
16. | /\baus\B/ |
passt auf 'außen' aber nicht 'aus' und auch nicht 'Haus' (Wortgrenze und "negative" Wortgrenze) |
17. | /^Hans/ |
passt auf 'Hans' nur am Anfang des zu durchsuchenden Bereichs |
18. | /Hans$/ |
passt auf 'Hans' nur am Ende des zu durchsuchenden Bereichs |
19. | /^\s*$/ |
passt auf Zeilen, die nur aus Leerzeichen und anderen Leerraumzeichen bestehen oder leer sind |
20. | /$Name/ |
interpretiert den Inhalt des Skalars $Name als regulären Ausdruck |
Wenn Sie in einem regulären Ausdruck nach einer bestimmten Zeichenkette suchen wollen, notieren Sie die Zeichenkette einfach zwischen den beiden Schrägstrichen des regulären Ausdrucks, so wie in Beispiel (1.). Allerdings gilt auch hier wie bei den regulären Ausdrücken für einzelne Zeichen: wenn Sie nach einer festen Zeichenfolge suchen, sind Sie mit der Funktion index besser beraten.
Reguläre Ausdrücke sind sozusagen eine eigene Sprache, die durch Wörter, die anhand grammatischer Regeln verknüpft werden, dargestellt wird. Die Verknüpfung erfolgt durch Operatoren. Der Grund, warum reguläre Ausdrücke so kompliziert erscheinen, ist die hohe Komprimierung in der Notation.
Ein Wort in der Sprache der regulären Ausdrücke wird Atom genannt. Atome stellen immer genau ein gesuchtes Zeichen dar, beispielsweise a
, [abc]
, .
oder \[
. Die Zeichenklasse [abc]
stellt ein Zeichen dar, das 'a', 'b' oder 'c' sein kann. Der Punkt .
ist die Abkürzung für eine ganz spezielle Zeichenklasse, die alle Zeichen außer dem Zeilenumbruch beinhaltet. Er entspricht also in der DOS-Eingabeaufforderung beispielsweise dem ?
. Das Konstrukt \[
stellt eine eckige Klammer dar, die aber durch den umgekehrten Schrägstrich maskiert werden muss, wenn sie nicht als Steuerzeichen verstanden werden soll.
Um aus Atomen ein zusammenhängendes Muster zu bilden, notieren Sie die Atome einfach ohne Leerzeichen aneinander.
Zeichenwiederholungen können Sie mit Wiederholungsoperatoren kennzeichnen.
Das Fragezeichen ?
bedeutet in einem regulären Ausdruck: das Zeichen vor dem Fragezeichen oder auch nicht. Siehe dazu Beispiel (2.).
Das Pluszeichen +
bedeutet: eine oder mehrere Wiederholungen des Zeichens, das vor dem Pluszeichen steht. Siehe dazu Beispiel (4.).
Das Sternzeichen *
bedeutet: keine, eine oder mehrere Wiederholungen des Zeichens, das vor dem Sternzeichen steht. Siehe dazu Beispiel (5.).
Wenn Sie vor den Zeichen +
oder *
einen Punkt notieren (der für ein beliebiges Zeichen steht), erzeugen Sie einen Platzhalter, der dem *
in der DOS/Windows-Welt, etwa bei Dateinamen, entspricht. Siehe dazu Beispiele (6.) bis (9.).
Geschweifte Klammern mit einer Zahl oder zwei Zahlen n darin {n}
stehen für n Wiederholungen des Zeichens vor der geschweiften Klammer an der betreffenden Stelle - siehe dazu Beispiele (10.) bis (12.). Dabei können Sie auch das Punktzeichen vor der geschweiften Klammer notieren. In diesem Fall bedeutet die Angabe innerhalb der geschweiften Klammer: so viele beliebige Zeichen wie angegeben - siehe dazu Beispiel (12.)
Sie können nach Zeichenketten suchen, die nur dann gefunden werden, wenn sie am Anfang oder am Ende eines Wortes vorkommen. Auch die Umkehrung davon ist möglich: Sie können nach Zeichenketten suchen, die nur dann gefunden werden, wenn sie nicht am Anfang oder am Ende eines Wortes vorkommen.
Mit \b
vor einer Zeichenkette wird die Zeichenkette nur gefunden, wenn ein Wort damit anfängt.
Mit \b
nach einer Zeichenkette wird die Zeichenkette nur gefunden, wenn ein Wort damit endet.
Mit \B
vor einer Zeichenkette wird die Zeichenkette nur gefunden, wenn ein Wort nicht damit anfängt.
Mit \B
nach einer Zeichenkette wird die Zeichenkette nur gefunden, wenn ein Wort nicht damit endet.
Zu diesen Möglichkeiten siehe Beispiele (13.) bis (16.).
Genau gesagt definiert \b
die Grenze zwischen \w
und \W
(oder Zeichenkettenanfang oder -ende).
Sie können Zeichenketten suchen, die nur dann gefunden werden, wenn sie am Anfang oder am Ende einer Zeile im zu durchsuchenden Bereich vorkommen. Dies ist vor allem im Zusammenhang mit Zeilen in Textdateien interessant.
Mit dem Hütchensymbol ^
am Beginn des Suchausdrucks wird die Zeichenkette nur gefunden, wenn sie am Anfang des Bereichs steht.
Mit dem Dollarzeichen $
am Ende des Suchausdrucks wird die Zeichenkette nur gefunden, wenn sie am Ende des Bereichs steht.
Zu diesen Möglichkeiten siehe Beispiele (17.) bis (19.).
Innerhalb von regulären Ausdrücken können Sie auch Variablen verwenden. Auf diese Weise können Sie dynamische Daten als Suchmuster einsetzen. Im Zusammenhang mit CGI können Sie z.B. die Anwendereingabe aus einem Formularfeld in ein Suchmuster übernehmen. Siehe dazu Beispiel (20.).
Da es bei regulären Ausdrücken einige Zeichen mit Sonderbedeutung gibt, müssen Sie solche Zeichen maskieren, wenn Sie nicht die Sonderbedeutung des Zeichens meinen, sondern seine literale, normale Bedeutung, also einen Senkrechtstrich als Senkrechtstrich oder einen Punkt als Punkt meinen. Das Maskierungszeichen ist in allen Fällen der Backslash.
Zeichen | Maskierung | Grund | Beispiel |
---|---|---|---|
/ |
\/ |
Wenn der Schrägstrich den regulären Ausdruck begrenzt, muss er innerhalb davon maskiert werden. | /\/usr\/bin\/perl/ |
. |
\. |
Der Punkt steht in regulären Ausdrücken ansonsten für ein beliebiges anderes Zeichen. | /Ende aus\./ |
+ |
\+ |
Das Pluszeichen steht ansonsten für ein oder mehrmaliges Vorkommen des davorstehenden Zeichens. | /\d\+\d/ |
* |
\* |
Das Sternzeichen steht ansonsten für kein, ein oder mehrmaliges Vorkommen des davorstehenden Zeichens. | /\*char/ |
? |
\? |
Das Fragezeichen steht ansonsten für kein oder einmaliges Vorkommen des davorstehenden Zeichens. | /Wie geht das\?/ |
^ |
\^ |
Das Dach- oder Hütchensymbol kann ansonsten eine Zeichenklasse verneinen oder bei Zeichenketten angeben, dass das nachfolgende Suchmuster am Anfang des Suchbereichs vorkommen muss. | /ein \^ über dem Kopf/ |
$ |
\$ |
Das Dollarzeichen kann einen Skalar einleiten oder bei Zeichenketten angeben, dass das voranstehende Suchmuster am Ende des Suchbereichs vorkommen muss. | /Preis (US-Dollar): \d*\$/ |
| |
\| |
Der Senkrechtstrich kann ansonsten alternative Ausdrücke auseinanderhalten. | /find (.*) \| sort/ |
\ |
\\ |
Der Backslash würde ansonsten das nachfolgende Zeichen maskieren. | /C:\\/ |
( ) |
\( \) |
Runde Klammern können ansonsten Teilausdrücke gruppieren und zum Merken einklammern. | /\(Hinweis: (.*)\)/ |
[] |
\[ \] |
Eckige Klammern begrenzen ansonsten eine Zeichenklasse. | /\$(.*)\[\d+\]/ |
{ } |
\{ \} |
Geschweifte Klammern bedeuten ansonsten eine Wiederholungs-Angabe für davorstehende Zeichen. | /ENV\{.*\}/ |
Normalerweise sind alle regulären Ausdrücke, die Wildcard-Ausdrücke wie .*
enthalten, sehr "gierig". Sie holen sich so viele Zeichen wie möglich. Es gibt jedoch die Möglichkeit, solche Ausdrücke zu mehr Genügsamkeit zu zwingen.
Anzeigebeispiel: So sieht's aus (Zum Aufruf des Scripts ist eine Internet-Verbindung erforderlich)
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title>\n"; print "</head><body>\n"; my $HTML_Zeile = "<html><head><title>Testausgabe</title></head><body><h1>Überschrift</h1></body></html>"; $HTML_Zeile =~ /(^<.+>)/; my $gierig = $1; $HTML_Zeile =~ /(^<.+?>)/; my $genuegsam = $1; $gierig =~ s/</</g; # nur wegen HTML-Ausgabe $gierig =~ s/>/>/g; # nur wegen HTML-Ausgabe $genuegsam =~ s/</</g; # nur wegen HTML-Ausgabe $genuegsam =~ s/>/>/g; # nur wegen HTML-Ausgabe print "<p><b>Gierige Version:</b> <tt>$gierig</tt></p>"; print "<p><b>Genügsame Version:</b> <tt>$genuegsam</tt></p>"; print "</body></html>\n";
Das Beispiel-Script demonstriert die Gier regulärer Ausdrücke und zeigt auch, wie sich diese Gier unterbinden lässt. Ein Skalar namens $HTML_Zeile
wird deklariert und erhält als Anfangswert den Code einer kompletten kleinen HTML-Datei. Anschließend wird dieser Skalar mit einem regulären Ausdruck bewertet, der darin nach einem Muster /(^<.+>)/
sucht. In runde Klammern eingeschlossen ist das gesamte Suchmuster, weil anschließend ausgegeben werden soll, was gefunden wurde. Das Suchergebnis wird im Skalar $gierig
gespeichert. Anschließend wird die Prozedur noch einmal wiederholt. Diesmal ist der reguläre Ausdruck nur minimal anders: er enthält hinter dem Pluszeichen noch ein Fragezeichen.
Beide Suchergebnisse werden anschließend noch für die HTML-Ausgabe vorbereitet, und zwar werden die spitzen Klammern HTML-gerecht ersetzt (siehe dazu auch Suchen und Ersetzen mit regulären Ausdrücken).
Die Ausgabe von $gierig
bewirkt:
<html><head><title>Testausgabe</title></head><body><h1>Überschrift</h1></body></html>
Die Ausgabe von $genuegsam
dagegen:
<html>
Der Wildcard-Ausdruck .+
, der "alles" bis zum Zeichen >
holen soll, macht nämlich nicht beim nächsten >
Stopp, sondern erst beim allerletzten. Durch das Anhängen des Fragezeichens, also durch Erweiterung auf .+?
, beschränkt sich das Muster auf das Auffinden des nächsten >
-Zeichens.
Sie können mehrere Suchausdrücke angeben. Dann passt der Ausdruck auf alle Zeichenketten, in denen wenigstens eine der Alternativen vorkommt.
Anzeigebeispiel: So sieht's aus (Zum Aufruf des Scripts ist eine Internet-Verbindung erforderlich)
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title>\n"; print "</head><body>\n"; my $Text = "Kaffee ohne Milch"; print "egal ob mit oder ohne<br>\n" if ($Text =~ /mit|ohne/); $Text = "Kaffee mit Milch"; print "sag ich doch: egal ob mit oder ohne<br>\n" if ($Text =~ /mit|ohne/); print "</body></html>\n";
Das Beispiel-Script deklariert einen Skalar $Text
mit dem Anfangswert Kaffee ohne Milch
. Abhängig vom Erfolg des regulären Ausdrucks /mit|ohne/
, der auf diesen Skalar angewendet wird, wird im aufrufenden Browser ausgegeben: egal ob mit oder ohne
. Der Senkrechtstrich |
teilt den regulären Ausdruck in zwei Alternativen auf, bei denen es reicht, wenn eine davon zutrifft. Da dies der Fall ist, wird der Satz im Browser ausgegeben. Zur Kontrolle wird der Text anschließend zu Kaffee mit Milch
geändert. Der anschließend angewendete gleiche reguläre Ausdruck führt wieder zum Erfolg, und es wird sag ich doch: egal ob mit oder ohne
ausgegeben.
Mit Hilfe von Klammerung einzelner Teile eines regulären Ausdrucks können Sie Teilmuster speichern und an einer späteren Stelle wiederverwenden.
Anzeigebeispiel: So sieht's aus (Zum Aufruf des Scripts ist eine Internet-Verbindung erforderlich)
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); print "Content-type: text/html\n\n"; print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">', "\n"; print "<html><head><title>Testausgabe</title>\n"; print "</head><body>\n"; my $CTIME = localtime(time); $CTIME =~ /^([A-Za-z]*?)\s*([A-Za-z]*?)\s*(\d*?)\s*(\d*?):(\d*?):(\d*)\s*(\d*)$/; my $Tag = $1; my $Monat = $2; my $Monatstag = $3; my $Stunden = $4; my $Minuten = $5; my $Sekunden = $6; my $Jahr = $7; my %Tage = (Mon => "Montag", Tue => "Dienstag", Wed => "Mittwoch", Thu => "Donnerstag", Fri => "Freitag", Sat => "Samstag", Sun => "Sonntag"); my %Monate = (Jan => "01", Feb => "02", Mar => "03", Apr => "04", May => "05", Jun => "06", Jul => "07", Aug => "08", Sep => "09", Oct => "10", Nov => "11", Dec => "12"); print "<b>Heute ist $Tage{$Tag}, der $Monatstag.$Monate{$Monat}.$Jahr, es ist $Stunden.$Minuten Uhr</b>\n"; print "</body></html>\n";
Das Beispiel ruft die Perl-Funktion localtime mit dem Rückgabewert der Funktion time auf und speichert den Rückgabewert von localtime
im Skalar $CTIME
. Darin ist anschließend eine Zeichenkette gespeichert, die so aufgebaut ist:
Sun Jun 17 21:37:40 2006
In der darauffolgenden Anweisung wird $CTIME
mit einem langen regulären Suchausdruck bewertet. Der reguläre Ausdruck versucht, das gesamte typische Muster des Datum-Uhrzeit-Strings zu erfassen. Die Nutzdaten darin, also Wochentag, Monatsname, Monatstag, Stunden, Minuten, Sekunden und Jahr werden innerhalb des regulären Ausdrucks geklammert. Jeden Inhalt dieser Klammern merkt sich Perl und stellt ihn in den vordefinierten Variablen $1
, $2
, $3
usw. zur Verfügung. Die anschließend deklarierten Skalare holen sich die Werte aus den Klammern, indem ihnen die entsprechenden vordefinierten Variablen zugewiesen werden.
Die beiden Hashes %Tage
und %Monate
werden zum Zweck eines deutschsprachigen Datum-Uhrzeit-Formats verwendet. Das Script gibt am Ende so etwas aus wie:
Heute ist Sonntag, der 18.02.2007, es ist 17.39 Uhr.
Die Sonderzeichen innerhalb von regulären Ausdrücken werden vom Perl-Interpreter nach einer bestimmten Rangfolge bewertet.
()
(Klammerung)+ * ? {#,#}
(Wiederholungsoperatoren)abc ^ $ \b \B
(Zeichen/Zeichenketten, Zeilenanfang/-ende, Wortanfang/-ende)|
(Alternativen)Dadurch ist jeder reguläre Ausdruck eindeutig bewertbar. Wenn Sie in einem Ausdruck jedoch anders bewerten möchten, als es nach der Rangfolge geschieht, können Sie innerhalb des Ausdrucks Klammern setzen, um eine andere Bewertung zu erzwingen.
/a|bc|d/ # findet 'a' oder 'bc' oder 'd' /(a|b)(c|d)/ # findet 'ac' oder 'ad' oder 'bc' oder 'bd'
Laut der Rangfolge haben Zeichen bzw. Zeichenketten Vorrang vor dem Trennzeichen für Alternativen. Mit Hilfe von Klammern können Sie eine andere Bewertung erzwingen (siehe Beispiel).
Wenn Sie die Klammern zur Bewertungsänderung benutzen möchten, ohne sich die entsprechenden Teilausdrücke merken zu wollen, können Sie auch Klammern benutzen, die nur gruppieren. Dabei wird direkt hinter der öffnenden Klammer die Zeichenfolge ?:
notiert, im Beispiel wäre das (?:a|b)(?:c|d)
.
Hinter dem beendenden Begrenzerzeichen (normalerweise: Schrägstrich) eines regulären Ausdrucks können noch ein oder mehrere Buchstaben notiert werden - so genannte Flags. Damit können Sie das Verhalten der Suche zusätzlich beeinflussen. Mit einer Notation wie /aus/g
suchen Sie beispielsweise global nach dem Vorkommen von aus
, und mit /aus/gim
suchen Sie die Zeichenfolge aus
global, egal ob groß oder klein geschrieben, und die Zeichenkette kann auch aus mehreren Zeilen bestehen. Flags können Sie also beliebig kombinieren. Die folgende Tabelle listet die möglichen Flags auf.
Flag | Bedeutung |
---|---|
c |
Bei einem auftretenden Fehler nicht die Suchposition zurücksetzen. |
e |
Führt bei Ersetzungen die Ersatzzeichenkette als Perl-Code aus. |
g |
Global suchen, d.h. alle Vorkommen finden. |
i |
Groß-/Kleinschreibung ignorieren |
m |
Zeichenketten können aus mehreren Zeilen bestehen |
o |
Suchmuster nur einmal anwenden |
s |
Zeichenketten als eine einzige Zeile betrachten |
x |
Erweiterte Syntax verwenden |
Reguläre Ausdrücke sind das Mittel, mit dem in Perl in Zeichenketten etwas gesucht und ersetzt wird.
Anzeigebeispiel: So sieht's aus (Zum Aufruf des Scripts ist eine Internet-Verbindung erforderlich)
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); print "Content-type: text/plain\n\n"; my $Text = "Franz jagt im komplett verwahrlosten Taxi quer durch Bayern 1234567890"; $Text =~ s/[a-z]| //gi; print "$Text\n";
Das Schema für alle Suche-Ersetze-Vorgänge in Perl lautet:
$Zeichenkette =~ s/Suchmuster/Ersatzzeichenkette/[Flags]
$Zeichenkette
ist ein Skalar, in dem eine Zeichenkette gespeichert ist, so wie etwa $Text
im obigen Beispiel 1. Dieser Skalar wird mit dem Operator =~
an die Ersetzung gebunden, d.h. der Suche-Ersetze-Vorgang gilt für den Inhalt des Skalars. Dahinter notieren Sie die Ersetzung. Sie wird durch ein kleines s
eingeleitet. Nach dem s
notieren Sie das erste Begrenzerzeichen (per Voreinstellung ein Schrägstrich), und danach das Suchmuster, das mit dem zweiten Begrenzerzeichen abgeschlossen wird. Danach folgen das Zeichen oder die Zeichenfolge, mit dem/mit der die Fundstellen ersetzt werden sollen, abgeschlossen wird dieses Ersetzungsmuster mit dem dritten Begrenzerzeichen. Falls benötigt, notieren Sie nach dem letzten Begrenzerzeichen noch Flags für den Such-Ersetze-Vorgang. Im Beispiel wurden folgende Flags verwendet:
g
sucht/ersetzt alle Fundstellen (ansonsten wird nur die erste Fundstelle ersetzt)
i
sucht/ersetzt Buchstaben unabhängig davon, ob sie groß oder klein geschrieben sind (ansonsten wird Groß-/Kleinschreibung unterschieden).
Im obigen Beispiel werden aus dem Skalar $Text
alle Buchstaben (groß und klein) und alle Leerzeichen entfernt. Es bleiben anschließend also nur noch die Ziffern am Ende stehen. Das Ergebnis wird zur Kontrolle ausgegeben.
Anzeigebeispiel: So sieht's aus (Zum Aufruf des Scripts ist eine Internet-Verbindung erforderlich)
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); print "Content-type: text/plain\n\n"; my $Text = "In München steht ein Hofbräuhaus, dort gibt es Bier in Maßen"; $Text =~ s/ä/ä/g; $Text =~ s/ö/ö/g; $Text =~ s/ü/ü/g; $Text =~ s/Ä/Ä/g; $Text =~ s/Ö/Ö/g; $Text =~ s/Ü/Ü/g; $Text =~ s/ß/ß/g; print "$Text\n";
In diesem Beispiel werden in $Text
alle deutschen Umlaute und scharfes S durch ihre HTML-gerechten Umschreibungen ersetzt. Das Ergebnis wird zur Kontrolle ausgegeben.
Anzeigebeispiel: So sieht's aus (Zum Aufruf des Scripts ist eine Internet-Verbindung erforderlich)
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); print "Content-type: text/plain\n\n"; my $Text = "Dieses Script dreht alle Wörter um"; $Text =~ s/(\w+)/reverse $1/ge; print "$Text\n";
In diesem Beispiel werden in $Text
alle Wörter mit Hilfe des e
-Flags und der reverse-Funktion umgedreht. Das Ergebnis wird zur Kontrolle ausgegeben.
Für "kleinere" Aufgaben wie Suchen und Ersetzen oder das Zählen von einzelnen Zeichen gibt es in Perl die Möglichkeit, ohne reguläre Ausdrücke zu arbeiten. Dafür gibt es eine spezielle Syntax, den Transliterationsoperator tr
.
Anzeigebeispiel: So sieht's aus (Zum Aufruf des Scripts ist eine Internet-Verbindung erforderlich)
#!/usr/bin/perl -w use strict; use CGI::Carp qw(fatalsToBrowser); print "Content-type: text/plain\n\n"; my $Prinzip = "abc"; $Prinzip =~ tr/ac/xy/; print "Prinzip = $Prinzip\n"; my $chinesisch = "chinesisches Roulette rigoros"; $chinesisch =~ tr/Rr/Ll/; print "chinesisch = $chinesisch\n"; my $Geschrei = "WIE GEHT DAS ALLES MIT PERL?"; $Geschrei =~ tr/A-Z/a-z/; print "Geschrei = $Geschrei\n"; my $Variablenname = "Sügümälüxümülä"; $Variablenname =~ tr/A-Za-z_0-9/_/c; print "Variablenname = $Variablenname\n"; my $unsauber = "ein Satz mit überflüssigen Leerzeichen"; $unsauber =~ tr/ //s; print "unsauber = $unsauber\n"; my $WSatz = "Wir Westerwälder Waschweiber wollen weiße Wäsche waschen"; my $WZaehler = ($WSatz =~ tr/Ww//); print "W/w kommt in WSatz $WZaehler mal vor!\n"; my $AchtBitWort = "überschüssig"; $AchtBitWort =~ tr/\200-\377/\000-\177/; print "AchtBitWort = $AchtBitWort\n"; my $ROT13_Satz = "ihr seid ja solche Deppen da!"; $ROT13_Satz =~ tr/a-zA-Z/n-za-mN-ZA-M/; print "ROT13_Satz = $ROT13_Satz\n";
Eine Transliteration besteht darin, einzelne Zeichen durch andere Zeichen zu ersetzen. Das Schema für eine Transliteration in Perl lautet:
$Zeichenkette =~ tr/Suchmuster/Ersetzmuster/[Optionen]
Dabei sind sowohl das Such- als auch das Ersetzungsmuster keine Zeichenketten, sondern nur einzelne Zeichen oder Zeichenbereiche. Die Muster sind sozusagen zwei Listen von Zeichen. Wenn in $Zeichenkette
ein Zeichen gefunden wird, das in der Suchliste vorkommt, wird es mit dem Zeichen ersetzt, das an derselben Position in der Ersetzungsliste steht.
Alle Beispiele des obigen Scripts sind gleich aufgebaut. Es wird ein Skalar mit einem "interessanten" Wert deklariert. Dann wird eine Transliteration auf diesen Wert angewendet, und anschließend wird das Ergebnis ausgegeben.
Im Fall von $Prinzip
wird das Prinzip der Transliteration deutlich: in dem Beispiel wird a
durch x
ersetzt und c
durch y
. Die Ausgabe lautet daher:
Prinzip = xby
Im Fall von $chinesisch
werden die Buchstaben R
und r
durch L
und l
ersetzt. Die Ausgabe lautet daher:
chinesisch = chinesisches Loulette ligolos
Im Fall von $Geschrei
werden alle Großbuchstaben durch entsprechende Kleinbuchstaben ersetzt (entspricht etwa der Funktion lc). Die Ausgabe lautet daher:
Geschrei = wie geht das alles mit perl?
Im Fall von $Variablenname
werden alle Zeichen, die kein Buchstabe von A bis Z oder a bis z oder eine Ziffer oder ein Unterstrich sind, durch den Unterstrich _
ersetzt. Die Ausgabe lautet daher:
Variablenname = S_g_m_l_x_m_l_
Im Fall von $unsauber
werden alle doppelten oder mehrfachen Leerzeichen entfernt. Die Ausgabe lautet daher:
unsauber = ein Satz mit überflüssigen Leerzeichen
Im Fall von $WSatz
wird sich der Rückgabewert einer Transliteration zu eigen gemacht. Dem Skalar $WSatz
passiert dabei nichts weiter, aber der Rückgabewert ermittelt, wie oft die Buchstaben W
oder w
in dem Satz vorkommen. Die Ausgabe lautet daher:
W/w kommt in WSatz 9 mal vor!
Im Fall von $AchtBitWort
werden alle Zeichen mit Zeichenwerten zwischen 128 und 255 in Zeichen mit entsprechenden Zeichenwerten zwischen 0 und 127 umgewandelt. Die Ausgabe lautet daher:
AchtBitWort = |berfl|ssig
Im Fall von $ROT13_Satz
werden alle Zeichen des ersten Alphabethälfte in solche der zweiten verwandelt und umgekehrt (sie werden sozusagen um 13 Zeichenwerte rotiert). Die Ausgabe lautet:
ROT13_Satz = vue frvq wn fbypur Qrccra qn!
(das ROT13-Prinzip wird in den Newsgroups manchmal angewendet, um Dinge zu sagen, die nicht jeder verstehen können soll).
Subroutinen | |
Operatoren | |
SELFHTML/Navigationshilfen Perl Perl-Sprachelemente |
© 2007 Impressum