| ## Reguläre Ausdrücke
| Allgemeines zu regulären Ausdrücken Reguläre Ausdrücke anwenden Reguläre Ausdrücke für einzelne Zeichen Reguläre Ausdrücke für Zeichenketten Maskierung von Zeichen in regulären Ausdrücken Gierige und genügsame Suchmuster Reguläre Ausdrücke mit Alternativen Teilausdrücke merken mit Klammerung Rangfolge in regulären Ausdrücken Flags hinter regulären Ausdrücken Suchen und Ersetzen mit regulären Ausdrücken Transliteration

## Allgemeines zu regulären Ausdrücken

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 WWW-Browser übertragen. 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.

## Reguläre Ausdrücke anwenden

Zwei kleine einführende Beispiele sollen zeigen, in welchen Situationen reguläre Ausdrücke typischerweise zum Einsatz kommen.

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/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&uuml;nchen");

    foreach(@Orte) {
     if( $_ =~ /^M/ ) {
      print "$_ f&auml;ngt mit M an<br>\n";
     }
    }

    print "</body></html>\n";

### Erläuterung:

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:

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/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://www.teamone.de/{TeamOne-Seiten}}";
    $Zeile =~ /\{link:(.*)\{(.*)\}\}/;
    my $Link = $1;
    my $Linktext = $2;
    print "<a href=\"$Link\">$Linktext</a>";

    print "</body></html>\n";

### Erläuterung:

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` an den Browser ausgibt.

Mit der Anweisung `$Zeile =~ /\{link:(.*)\{(.*)\}\}/;` wird auf den Wert des Skalars `$Zeile` der reguläre Ausdruck angewendet, der zwischen den beiden Schrägstrichen steht. Um die fürchterliche Ansammlung von Zeichen erst mal 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 mal eine öffnende geschweifte Klammer `{` in dem durchsuchten Wert vorkommen. Dahinter kann wieder kommen was will, also `.*`, und am Ende sollen noch mal 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 werden sich auf diese Weise zwei variablen Bereiche gemerkt:
`{link:`http://www.teamone.de/`{`TeamOne-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.

### Beachten Sie:

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 übergebender Parameter vorkommen, beispielsweise in der Funktion split.

## Reguläre Ausdrücke für einzelne Zeichen

Sie können in einer Zeichenkette

- nach einem bestimmten Zeichen suchen
- nach mehreren bestimmten Zeichen suchen
- nach einem Zeichen aus einem bestimmten Bereich suchen

Solche Ausdrücke eignen sich weniger zur Mustererkennung als dazu, um 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 Zeichencodierung) 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 Ausrü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, in dem 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]` enspricht `\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, daß 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 paßsst, 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 die abgekürzten Zeichenklassen wie etwa `\s` oder `\d` zu negieren, ändern Sie einfach den "Namen" der Abkürzung in einen Großbuchstaben, also `\S` oder `\D`.

## Reguläre Ausdrücke für Zeichenketten

Sie können

- nach einer bestimmten Zeichenkette suchen
- nach einer Zeichenketten mit Gruppierungsoperatoren (Platzhalter, Wildcards) suchen
- nach Zeichenketten am Anfang oder Ende eines Wortes suchen
- nach Zeichenketten am Anfang oder Ende einer Zeile suchen

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' aber nicht 'Hase'
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 'aussen' aber nicht 'Haus' (Wortgrenze)
15. | `/\baus\b/` | passt auf 'aus' aber nicht 'Haus' und auch nicht 'aussen' (Wortgrenze)
16. | `/\baus\B/` | passt auf 'aussen' 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 Ausrü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önnte Sie z.B. die Anwendereingabe aus einem Formularfeld in ein Suchmuster übernehmen. Siehe dazu Beispiel (20.).

## Maskierung von Zeichen in regulären Ausdrücken

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, muß 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 kein, ein oder mehrmaliges Vorkommen des davorstehenden Zeichens. | `/\d\+\d/`
`*` | `\*` | Das Sternzeichen steht ansonsten für 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/`
`( )` | `\( \)` | 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 Wiederholungsangabe für davorstehende Zeichen. | `/ENV\{.*\}/`

## Gierige und genügsame Suchmuster

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.

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/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>&Uuml;berschrift</h1></body></html>";

    $HTML_Zeile =~ /(^<.+>)/;
    my $gierig = $1;
    $HTML_Zeile =~ /(^<.+?>)/;
    my $genuegsam = $1;

    $gierig =~ s/</&lt;/g;    # nur wegen HTML-Ausgabe
    $gierig =~ s/>/&gt;/g;    # nur wegen HTML-Ausgabe
    $genuegsam =~ s/</&lt;/g; # nur wegen HTML-Ausgabe
    $genuegsam =~ s/>/&gt;/g; # nur wegen HTML-Ausgabe

    print "<p><b>Gierige Version:</b> <tt>$gierig</tt></p>";
    print "<p><b>Gen&uuml;gsame Version:</b> <tt>$genuegsam</tt></p>";

    print "</body></html>\n";

### Erläuterung:

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 mal 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.

## Reguläre Ausdrücke mit Alternativen

Sie können mehrere Suchausdrücke angeben. Dann passt der Ausdruck auf alle Zeichenketten, in denen wenigstens eine der Alternativen vorkommt.

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/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";

### Erläuterung:

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 auf in zwei Alternativen, 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 anschleßend angewendete gleiche reguläre Ausdruck führt wieder zum Erfolg, und es wird `sag ich doch: egal ob mit oder ohne` ausgegeben.

## Teilausdrücke merken mit Klammerung

Mit Hilfe von Klammerung einzelner Teile eines regulären Ausdrucks können Sie Teilmuster speichern und an einer späteren Stelle wiederverwenden.

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/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";

### Erläuterung:

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 2001`

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 17.06.2001, es ist 21.37 Uhr.

## Rangfolge in regulären Ausdrücken

Die Sonderzeichen innerhalb von regulären Ausdrücken werden vom Perl-Interpreter nach einer bestimmten Rangfolge bewertet.

1. Rangstufe: `()` (Klammerung)
2. Rangstufe: `+ * ? {#,#}` (Wiederholungsoperatoren)
3. Rangstufe: `abc ^ $ \b \B` (Zeichen/Zeichenketten, Zeilenanfang/-ende, Wortanfang/-ende)
4. Rangstufe: `|` (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.

### Beispiele:

    /a|bc|d/       # findet 'a' oder 'bc' oder 'd'
    /(a|b)(c|d)/   # findet 'ac' oder 'ad' oder 'bc' oder 'bd'

### Erläuterung:

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)`.

## Flags hinter regulären Ausdrücken

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.
`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

## Suchen und Ersetzen mit regulären Ausdrücken

Reguläre Ausdrücke sind das Mittel, mit dem in Perl in Zeichenketten etwas gesucht und ersetzt wird.

### Beispiel 1 eines vollständigen CGI-Scripts in Perl:

    #!/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";

### Erläuterung:

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, durch die Fundstellen ersetzt werden sollen, die mit dem dritten Begrenzerzeichen abgeschlossen werden. 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.

### Beispiel 2 eines vollständigen CGI-Scripts in Perl:

    #!/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/ä/&auml;/g;
    $Text =~ s/ö/&ouml;/g;
    $Text =~ s/ü/&uuml;/g;
    $Text =~ s/Ä/&Auml;/g;
    $Text =~ s/Ö/&Ouml;/g;
    $Text =~ s/Ü/&Uuml;/g;
    $Text =~ s/ß/&szlig;/g;

    print "$Text\n";

### Erläuterung:

Im diesem Beispiel werden in `$Text` alle deutschen Umlaute und scharfes S durch ihre HTML-gerechten Umschreibungen ersetzt. Das Ergebnis wird zur Kontrolle ausgegeben.

## Transliteration

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`.

### Beispiel eines vollständigen CGI-Scripts in Perl:

    #!/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";

### Erläuterung:

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 Suchmuster als auch das Ersetzmuster 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 zueigen 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 Zeichenwerte 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

© 2001 selfhtml@teamone.de