SELFHTML/Quickbar CGI/Perl Perl-Sprachelemente

| ## 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 Reguläre Ausdrücke mit Alternativen Rangfolge und Klammerung in regulären Ausdrücken Teilausdrücke mit Klammerung

## Allgemeines zu regulären Ausdrücken

Reguläre Ausdrücke sind genau definierte Suchmuster für Zeichen und Zeichenketten. Mit Hilfe dieser Suchmuster können Sie beispielsweise Variableninhalte durchsuchen und bearbeiten. Für CGI-Aufgaben sind reguläre Ausdrücke enorm wichtig. Zum Beispiel läßt sich der Datenstrom eines HTML-Formulars, der an ein CGI-Programm beim Absenden des Formulars übergeben wird, mit Hilfe von regulären Ausdrücken in seine einzelnen Bestandteile zerlegen. Genauso können Sie mit Hilfe von regulären Ausdrücken 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. Und schließlich sind reguläre Ausdrücke ein mächtiges Mittel, um große Datenbestände nach komplexen Suchausdrücken zu durchforsten.

Reguläre Ausdrücke sind allerdings für Neulinge 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 sofort zurecht.

## Reguläre Ausdrücke anwenden

Um reguläre Ausdrücke anzuwenden, müssen Sie wissen, welche Möglichkeiten es dazu gibt.

### Beispiel 1:

    #!/usr/bin/perl

    $Daten = $ENV{'PATH'};
    if($Daten =~ /PERL/)    # Ob darin wohl die Zeichenfolge 'PERL' vorkommt?
     { print "Aha, in Ihrer PATH-Variablen kommt PERL vor!\n"; }
    else
     { print "in Ihrer PATH-Variablen kommt PERL leider nicht vor!\n"; }

### Beispiel 2:

    #!/usr/bin/perl

    @Orte = ("Berlin","Paris","London","Madrid","Athen","Rom","Lissabon","Stockholm","Kopenhagen");

    for(@Orte)
     {
      if(/[MKS]/)   # Alle Orte, in denen 'M', 'K' oder 'S' vorkommt
       { print "Die Stadt ", $_, " entspricht dem Suchmuster\n"; }
     }

### Beispiel 3:

    #!/usr/bin/perl

    open(LOGDATEI,"<access.log");
    $Zugriffe = 0;

    while(<LOGDATEI>)
     {
      /index.htm/ ? $Zugriffe = $Zugriffe + 1 : $Zugriffe = $Zugriffe;
     }
    print $Zugriffe, " Zugriffe auf Datei index.htm!\n";
    close(LOGDATEI);

### Erläuterung:

Einen regulären Ausdruck erkennen Sie in Perl normalerweise an zwei Schrägstrichen `/.../`. Zwischen den Schrägstrichen steht jeweils der reguläre Ausdruck.

Wenn Sie einen regulären Ausdruck einsetzen wollen, brauchen Sie zunächst etwas, das Sie durchsuchen wollen. Das kann beispielsweise der Wert sein, der in einem Skalar gespeichert ist, so wie im obigen Beispiel 1, oder die Werte, die in den Elementen einer Liste vorkommen, so wie im obigen Beispiel 2, oder auch die einzelnen Zeilen einer Datei, so wie im obigen Beispiel 3.

In Beispiel 1 wird in der Umgebungsvariablen PATH nach der Zeichenfolge "PERL" gesucht. Beachten Sie, daß eine solche Zeichenfolge innerhalb eines regulären Ausdrucks ohne Anführungszeichen notiert wird. Im Beispiel wird der Inhalt von `$ENV{'PATH'}` in einem Skalar `$Daten` gespeichert. Mit `if($Daten =~ /PERL/)` wird der Wert dieses Skalars nach der Zeichenfolge "PERL" durchsucht. Wichtig ist dabei der Abfrage-Operator `=~`. Mit if-Ausdrücken von der Art `if($Skalarname =~ /reg.Ausdruck/)` können Sie also beliebige Skalare nach beliebigen Inhalten durchsuchen.

In Beispiel 2 wird eine Liste mit Städtenamen definiert. Innerhalb der for-Schleife werden alle Listenelemente, also die Stadtenamen, danach durchsucht, ob in ihnen einer der Großbuchstaben M, K oder S vorkommt. Die Suche wird mit `if(/[MKS]/)` formuliert. In diesem Fall wird im Gegensatz zu Beispiel 1 kein Abfrage-Operator eingesetzt. Die Abfrage bezieht sich ja aufgrund der Schleife immer auf das aktuelle Element der Liste. Sie könnten die Abfrage auch mit der vordefinierten Variablen `$_` in der Form `if($_ =~ /[MKS]/)` notieren. Da es aber klar ist, daß deren Wert gemeint ist, genügt die Kurzform `if(/[MKS]/)`.

In Beispiel 3 wird eine `Logdatei` zeilenweise eingelesen. In dieser Datei wird nach dem Vorkommen von "index.htm" gesucht. Wenn eine Zeile mit dieser Zeichenfolge gefunden wird, wird ein Zugriffszähler erhöht, wenn nicht, bleibt der Zugriffszähler unverändert. Am Ende wird die so ermittelte Anzahl der Zugriffe auf index.htm ausgegeben. Der reguläre Ausdruck kommt in diesem Beispiel in einer einfachen Entweder-Oder-Abfrage vor. Der reguläre Ausdruck wird dabei einfach danach bewertet, ob er wahr oder falsch ist. Wenn er wahr ist (wenn "index.htm" in der aktuellen Zeile vorkommt), wird die Anweisung links vom Doppelpunkt ausgeführt, wenn er falsch ist, die Anweisung rechts vom Doppelpunkt.
(Zum Thema Dateien siehe auch Dateien lesen und schreiben).

### Beachten Sie:

Ein wichtiger Anwendungsbereich für reguläre Ausdrücke ist auch das Suchen und Ersetzen bei Zeichenketten. Reguläre Ausdrücke können ferner in einigen Perl-Funktionen als zu übergebender Parameter vorkommen.

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

Sie können

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

Die folgenden Beispiele sind numeriert, z.B. mit ( 1). Diese Numerierungen gehören nicht zu den regulären Ausdrücken, sie dienen nur als Bezug für die Erläuterungen zu den Beispielen.

### Beispiele:

    ( 1) /a/            # findet 'a'
    ( 2) /[ab]/         # findet 'a' oder 'b'
    ( 3) /[A-Z]/        # findet Grossbuchstaben
    ( 4) /[0-9]/        # findet Ziffern
    ( 5) /\d/           # findet Ziffern - genau wie ( 4)
    ( 6) /\D/           # findet alles ausser Ziffern
    ( 7) /[0-9]\-/      # findet Ziffern oder Minuszeichen
    ( 8) /[\[\]]/       # findet alles, worin eckige Klammern vorkommen
    ( 9) /[a-zA-Z0-9_]/ # findet Buchstaben, Ziffern oder Unterstrich
    (10) /[\w]/         # findet Buchstaben, Ziffern oder Unterstrich - genau wie ( 9)
    (11) /[\W]/         # findet alles ausser Buchstaben, Ziffern oder Unterstrich
    (12) /[\r]/         # findet das Steuerzeichen für Wagenrücklauf (DOS-typisch)
    (13) /[\n]/         # findet das Steuerzeichen für Zeilenvorschub
    (14) /[\t]/         # findet das Steuerzeichen für Tabulator
    (15) /[\f]/         # findet das Steuerzeichen für Seitenvorschub
    (16) /[\s]/         # findet Leerzeichen sowie Steuerzeichen aus (12-15)
    (17) /[\S]/         # findet alles ausser Leerzeichen und Steuerzeichen aus (12-15)
    (18) /[^äöüÄÖÜ]/    # findet alles, worin keine deutschen Umlaute vorkommen
    (19) /[^a-zA-Z]/    # findet alles, worin keine Buchstaben vorkommen
    (20) /[ab]/s        # findet 'a' oder 'b' auch zeilenübergreifend

### Erläuterung:

Wenn Sie in einem regulären Ausdruck nach einzelnen Zeichen suchen sollen, müssen Sie den Suchausdruck in Schrägstriche und zusätzlich in eckige Klammern setzen. Nur wenn Sie nach einem einzelnen Zeichen suchen, wie im Beispiel (1), können Sie die eckigen Klammern weglassen. Wenn Sie mehrere Zeichen ohne eckige Klammern notieren, werden diese als Zeichenkette interpretiert.

Wenn Sie nach einer Gruppe bestimmter Zeichen suchen wollen, notieren Sie diese einfach innerhalb der eckigen Klammern, so wie in Beispiel (2).

Wenn Sie nach Zeichenbereichen suchen wollen, z.B. nach Buchstaben der ersten Hälfte des Alphabets oder nach Ziffern, markieren Sie den gewünschten Bereich durch das Anfangszeichen, ein Minuszeichen als Bindestrich, und das Endzeichen, so wie in den Beispielen (3) und (4).

Wenn Sie nach einem der Zeichen +-?.*^$()[]{}|\ suchen wollen, notieren Sie vor dem Zeichen einen umgekehrten Schrägstrich `\`, so wie in den Beispielen (7) und (8).

Es gibt einige spezielle Suchmuster, die aus einem umgekehrten Schrägstrich und einem Schlüsselbuchstaben bestehen. Die Beispiele (5)/(6), (10) bis (17) zeigen diese Suchmuster.

Sie können auch eine Negativsuche veranlassen. Dazu notieren Sie das Dachzeichen `^` vor den gewünschten Zeichen oder Zeichenbereichen. Eine solche Suche bewirkt, das nur Stellen gefunden werden, die die angegebenen Zeichen nicht enthalten. Die Beispiele (18) und (19) zeigen Anwendungsfälle dafür.

Für mehrzeilige Suchen müssen Sie an den regulären Ausdruck hinter dem beendenden Schrägstrich ein `s` notieren - siehe Beispiel (20).

## 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

Die folgenden Beispiele sind numeriert, z.B. mit ( 1). Diese Numerierungen gehören nicht zu den regulären Ausdrücken, sie dienen nur als Bezug für die Erläuterungen zu den Beispielen.

### Beispiele:

    ( 1) /aus/          # findet 'aus' - auch in 'Haus' oder 'Mausi'
    ( 2) /aus?/         # findet 'aus' usw. - aber auch 'au' und 'auf'
    ( 3) /a./           # findet 'ab' und 'an'
                        # (ein beliebiges Zeichen hinter 'a')
    ( 4) /a+/           # findet 'a' und 'aa' und 'aaaaa'
                        # (ein oder beliebig viele 'a')
    ( 5) /a*/           # findet 'a' und 'aa' und 'aaaaa' und 'b'
                        # (kein oder beliebig viele 'a')
    ( 6) /Ha.s/         # findet 'Haus' und 'Hans' aber nicht 'Hannes'
    ( 7) /Ha.+s/        # findet 'Haus' und 'Hans' und 'Hannes'
                        # (ein oder beliebig viele beliebige Zeichen)
    ( 8) /Ha.s/         # findet 'Haus' und 'Hans' aber nicht 'Hase'
    ( 9) /Ha.?s/        # findet 'Haus' und 'Hans' und 'Hase'
    (10) /x{10,20}/     # findet zwischen 10 und 20 'x' in Folge
    (11) /x{10,}/       # findet 10 und mehr 'x' in Folge
    (12) /x.{2}y/       # findet nur 'xxxy'
    (13) /Hans\b/       # findet 'Hans' aber nicht 'Hansel'
    (14) /\baus/        # findet 'aus' oder 'aussen' aber nicht 'Haus'
    (15) /\baus\b/      # findet 'aus' aber nicht 'Haus' und auch nicht 'aussen'
    (16) /\baus\B/      # findet 'aussen' aber nicht 'aus' und auch nicht 'Haus'
    (17) /^Hans/        # findet 'Hans' nur am Anfang des zu durchsuchenden Bereichs
    (18) /Hans$/        # findet 'Hans' nur am Ende des zu durchsuchenden Bereichs
    (19) /^\s*$/        # findet Zeilen, die nur aus Leerzeichen und ähnlichem bestehen
    (20) /$Name/        # findet den Inhalt des Skalars $Name
    (21) /aus/s         # findet 'aus' auch zeilenübergreifend

### Erläuterung:

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

Es gibt bei den regulären Ausdrücken verschiedene sogenannte Gruppierungsoperatoren. Untereinander verknüpft oder in komplexere Ausdrücke gestellt, können Sie mit Gruppierungsoperatoren Platzhaltersuchen durchführen:
Der Punkt `.` steht für genau ein beliebiges Zeichen an der betreffenden Stelle - siehe dazu Beispiel (3). Wenn Sie aus der DOS/Windows-Welt kommen - der Punkt in einem regulären Ausdruck entspricht dort dem Fragezeichen-Platzhalter, etwa bei Dateinamen.
Das Fragezeichen `?` dagegen 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).

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ütchenzeichen `^` am Beginn des Suchausdrucks wird die Zeichenkette nur gefunden, wenn sie am Anfang der Zeile steht.
Mit dem Dollarzeichen `$` am Ende des Suchausdrucks wird die Zeichenkette nur gefunden, wenn sie am Ende der Zeile 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 in einem Formularfeld in das Suchmuster übernehmen. Siehe dazu Beispiel (20).

Für mehrzeilige Suchen müssen Sie an den regulären Ausdruck hinter dem beendenden Schrägstrich ein `s` notieren - siehe Beispiel (21).

## Reguläre Ausdrücke mit Alternativen

Sie können mehrere Suchausdrücke angeben. Dann werden alle Stellen gefunden, in denen wenigstens eine der Alternativen vorkommt.

### Beispiele:

    /a|b/          # findet 'a' oder 'b' - identisch mit /[ab]/
    /mit|ohne/     # findet 'mit' und 'Schmitt' aber auch 'ohne' und 'Bohne'

### Erläuterung:

Alternativen markieren Sie durch das Zeichen `|`. Im ersten der obigen Beispiele wird eine Alternative mit zwei einzelnen Zeichen formuliert. Dies wird in der Praxis jedoch nur selten verwendet, da die Schreibweiste `/[ab]/`, die das gleiche bedeutet, üblicher dafür ist.
Im zweiten der Beispiele wird nach zwei alternativen Zeichenketten gesucht. Jede Fundstelle mit einer der beiden Alternativen gehört zu den Suchtreffern. Sie können natürlich auch mehr als zwei Alternativen notieren.
Bei den einzelnen Alternativen sind alle übrigen Möglichkeiten regulärer Ausdrücke erlaubt.

## Rangfolge und Klammerung 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: `+ * ? {#,#}` (Gruppierungsoperatoren)
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).

## Teilausdrücke mit Klammerung

Für komplexe reguläre Ausdrücke können Sie mit Hilfe von Klammerung einzelne Teile des regulären Ausdrucks speichern und an einer späteren Stelle innerhalb des gleichen Ausdrucks referenzieren.

### Beispiel:

    #!/usr/bin/perl

    $Satz = "Was denn wohl der Mann mit der Frau da unter der Bettdecke macht?";
    if($Satz =~ /(\bder\b).*\1/)
     { print $1; }

### Erläuterung:

In dem Beispiel wird überprüft, ob in `$Satz` das Wort 'der' mehr als einmal vorkommt.

Dazu wird zunächst das, wonach "eigentlich" gesucht werden soll, in Klammern gesetzt. Im Beispiel soll nach einem separaten Wort 'der' gesucht werden, daher lautet die Formulierung im regulären Ausdruck `\bder\b`. Dieser Teilausdruck wird in Klammern gesetzt. Dadurch merkt sich der Perl-Interpreter diesen Teilausdruck. Dahinter folgt mit `.*` die Anweisung: hinter dem Wort 'der' kann folgen, was will. Die Syntax `\1` schließlich referenziert die zuvor definierte Klammer. Das heißt: wenn der Perl-Interpreter das Wort 'der' findet, schaut er nach, ob das Wort schon einmal gefunden wurde.
Wenn Sie zwei oder mehr solcher Klammern in einem regulären Ausdruck haben, können Sie diese Klammern mit `\1`, `\2`, `\3` usw. referenzieren. Dazu gibt es dann entsprechende vordefinierte Variablen in Perl, nämlich `$1`, `$2`, `$3` usw.

Die Ausgabe `print $1` im obigen Beispiel gibt den Inhalt von `$1` aus. Darin ist im Beispiel das Wort 'der' gespeichert, aber nur, weil es in dem Satz mehr als einmal vorkommt.

weiter: | Steuerzeichen und besondere Notationen
zurück: | Operatoren

SELFHTML/Quickbar CGI/Perl Perl-Sprachelemente

© 1998 Stefan Münz, muenz@csi.com