Der qr/.../-Operator und Regex-Objekte

(Auszug aus "Reguläre Ausdrücke" von Jeffrey E. F. Friedl)

Der qr/.../-Operator wurde unter Erweiterte einführende Beispiele und Die Kunst, reguläre Ausdrücke zu schreiben kurz behandelt (siehe Eine Regex-Sammlung, Eine helfende Hand führt die Maschine). Er ist ein unärer Operator, der eine Regex als Operand erwartet und ein Regex-Objekt zurückgibt. Dieses Objekt kann bei einer Substitution, einem Matching oder als Regex-Operand bei split eingesetzt werden, oder es kann als Teil einer größeren Regex verwendet werden.

Regex-Objekte werden vor allem dazu verwendet, zusammengehörige Teile einer Regex in einer Variablen zu verpacken, so dass man auf übersichtliche Art große reguläre Ausdrücke aufbauen kann. Man kann damit auch die Kompilierung der Regex und damit die Effizienz beeinflussen (mehr dazu später in diesem Abschnitt).

Wie bei Begrenzungszeichen für den Regex-Operanden erwähnt wurde, kann man die Begrenzungszeichen selbst auswählen, beispielsweise qr{...} oder qr!...!. Die fünf allgemeinen Modifikatoren /i, /x, /s, /m und /o werden unterstützt.

Regex-Objekte aufbauen und verwenden

Das folgende Programmstück variiert eines aus Erweiterte einführende Beispiele (unter Eine Regex-Sammlung):

my $HostnameRegex = qr/[-a-z0-9]+(?:\.[-a-z0-9]+)*\.(?:com|edu|info)/i;
my $HttpUrl = qr{
   http:// $HostnameRegex \b              # Hostname
   (?:
        / [-a-z0-9_:\@&?=+,.!/~*'%\$]*    # Optionaler Pfad ...
           (?<![.,?!])                    # ... darf nicht mit [.,?!] enden.
   )?
}ix;

In der ersten Zeile wird unsere einfache Regex für Hostnamen in ein Regex-Objekt gekapselt und in der Variablen $HostnameRegex abgelegt. In den folgenden Zeilen wird dieses Objekt zum Aufbau eines größeren Objekts verwendet, das eine HTTP-URL erkennt; dieses Objekt wird in der Variablen $HttpUrl gespeichert. Mit einem solchen Objekt kann man Texte untersuchen:

if ($text =~ $HttpUrl) {
   print "Text enthält eine URL\n";
}

Man kann auch gleich die darin vorkommenden HTTP-URLs herausschreiben:

while ($text =~ m/($HttpUrl)/g) {
   print "URL gefunden: $1\n";
}

Wir können nun unsere einfache Definition von $HostnameRegex durch die ausgefeiltere aus Regex-Methoden aus der Praxis (siehe unter Einen Hostnamen auf syntaktische Korrektheit prüfen) ersetzen:

my $HostnameRegex = qr{
   # Einen oder mehrere Teile, durch Punkte getrennt ...
   (?: [a-z0-9]\. | [a-z0-9][-a-z0-9]{0,61}[a-z0-9]\. )*
   # Top-level-Domains ...
   (?: com|edu|gov|int|mil|net|org|biz|info|...|aero|[a-z][a-z] )
}xi;

Dieses Regex-Objekt können wir genauso wie das vorherige, einfachere verwenden, ohne dass etwas dazwischenkommt (es enthält kein ˹^˼ und kein ˹$˼ an den Enden, und auch keine einfangenden Klammern). Damit erhalten wir automatisch eine bessere, spezifischere Regex für unser $HttpUrl.

Match-Modifikatoren bleiben kleben

Bei qr/.../ werden die fünf allgemeinen Modifikatoren unterstützt (siehe Regex-Modifikatoren). Wenn bei der Erzeugung eines Regex-Objekts ein solcher Modifikator angegeben wird, kann er nachträglich nicht mehr geändert werden, auch dann nicht, wenn das Objekt innerhalb eines m/.../-Operators mit ganz anderen Modifikatoren benutzt wird. Zum Beispiel funktioniert das Folgende nicht wie gewünscht:

my $WordRegex = qr/\b \w+ \b/; # Hoppla, der /x-Modifikator fehlt
   .
   .
   .
if ($text =~ m/^($WordRegex)/x) {
      print "Wort am Anfang gefunden: $1\n";
}

Der /x-Modifikator soll hier offensichtlich darauf wirken, wie $WordRegex verwendet wird, aber das geht nicht, weil die Modifikatoren (oder auch die fehlenden Modifikatoren) des Regex-Objekts vom qr/.../-Operator beim Erzeugen des Objekts fest mit diesem verbunden werden. Die Modifikatoren müssen also schon bei der Erzeugung des Objekts angegeben werden.

Das ergibt folgende funktionierende Version:

my $WordRegex = qr/\b \w+ \b/x;  # Funktioniert!
   .
   . 
   .
if ($text =~ m/^($WordRegex)/) {
      print "Wort am Anfang gefunden: $1\n";
}

Vergleichen wir die ursprüngliche Version nun aber mit dieser:

my $WordRegex = '\b \w+ \b';  # Normale String-Zuweisung.
   .
   . 
   .
if ($text =~ m/^($WordRegex)/x) {
      print "Wort am Anfang gefunden: $1\n";
}

Im Gegensatz zum Original funktioniert diese Version, auch wenn hier bei der Zuweisung an $WordRegex kein Modifikator angegeben wird. In diesem Fall ist $WordRegex eine normale Variable, die einen String enthält, der später bei der m/.../-Anweisung in ein Regex-Literal interpoliert wird. Es ist aus verschiedenen Gründen viel mühsamer, eine Regex aus Strings statt aus Regex-Objekten aufzubauen, unter anderem, weil man wie in diesem Fall daran denken muss, dass $WordRegex nur zusammen mit dem /x-Modifikator benutzt werden darf.

Man könnte in diesem Fall das Problem mit geklammerten Modus-Modifikatoren (siehe Modus-Modifikatoren mit Klammerung) innerhalb der Regex lösen:

my $WordRegex = '(?x:\b \w+ \b)'; # Normale String-Zuweisung.
   . 
   . 
   .
if ($text =~ m/^($WordRegex)/) {
      print "Wort am Anfang gefunden: $1\n";
}

Nachdem das Regex-Literal in m/.../ den String interpoliert hat, bekommt die Maschine die Regex ˹^((?x:\b\w+\b), und diese macht, was wir wollen.

Genau das passiert beim Erzeugen eines Regex-Objekts, außer dass bei einem Regex-Objekt immer alle vier Modifikatoren /i, /x, /m und /s explizit ein- oder ausgeschaltet werden. Mit qr/\b\w+\b/x wird ein Objekt erzeugt, das als String die Form ˹(?x-ism:\b\w+\b)˼ hätte. Beachten Sie, wie in der Klammer ˹(?x-ism:...)˼ der /x-Modifikator aktiviert wird und die anderen Modifikatoren /i, /s und /m abgeschaltet werden. Auf diese Weise bleiben die Modifikatoren immer an einem mit qr/.../ erzeugten Objekt kleben, ob sie nun explizit angegeben wurden oder nicht.

Regex-Objekte anschauen

Im letzten Abschnitt wurde erklärt, wie Regex-Objekte – logisch gesehen – in Klammern mit Modus-Modifikatoren eingepackt werden, wie bei ˹(?x-ism:...)˼. Man kann diese Klammern auch sichtbar machen. Wenn man ein Regex-Objekt dort verwendet, wo Perl einen String erwartet, gibt Perl netterweise eine String-Darstellung des entsprechenden Objekts aus. Zum Beispiel:

% perl -e 'print qr/\b \w+ \b/x, "\n"'
(?x-ism:\b \w+ \b)

So sieht die Text-Darstellung des $HttpUrl-Objekts von weiter oben aus:

(?ix-sm:
   http:// (?ix-sm:
   # Einen oder mehrere Teile, durch Punkte getrennt ...
   (?: [a-z0-9]\. | [a-z0-9][-a-z0-9]{0,61}[a-z0-9]\. )*
   # Top-level-Domains ...
   (?: com|edu|gov|int|mil|net|org|biz|info|...|aero|[a-z][a-z] )
) \b          # Hostname
   (?:
        / [-a-z0-9_:\@&?=+,.!/~*'%\$]* # Optionaler Pfad ...
           (?<![.,?!])                 # ... darf nicht mit [.,?!] enden.
   )?
)

Die String-Darstellung von Regex-Objekten ist für das Debugging sehr nützlich.

Regex-Objekte zur Effizienzsteigerung

Wenn man Regex-Objekte verwendet, kann man genau steuern, in welchem Moment Perl eine Regex in die interne Form kompiliert. Unter Die Kunst, reguläre Ausdrücke zu schreiben wurde Allgemeines zur Komplilierung von regulären Ausdrücken erwähnt, die komplexeren, aber auch Perl-spezifischen Belange werden im Abschnitt Regex-Kompilierung, der /o-Modifikator, qr/.../ und Effizienz erklärt.

  

<< zurück vor >>

 

 

 

Tipp der data2type-Redaktion:
Zum Thema Reguläre Ausdrücke bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:
   

Copyright der deutschen Ausgabe © 2008 by O’Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "Reguläre Ausdrücke" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

O’Reilly Verlag GmbH & Co. KG, Balthasarstr. 81, 50670 Köln