Regex-Operanden und Regex-Literale

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

Die untersten Einträge in der Tabelle Elemente von regulären Ausdrücken in Perl – Übersicht sind mit »Nur in Regex-Literalen« überschrieben. Ein Regex-Literal ist der »Regex«-Teil in m/Regex/, also das, was salopperweise oft einfach, aber etwas ungenau als »regulärer Ausdruck« bezeichnet wird. Der Teil zwischen den Schrägstrichen wird aber nach seinen eigenen, ganz bestimmten Regeln analysiert, bevor er an die Regex-Maschine weitergegeben wird. Diese Regeln sind denen bei Strings in Anführungszeichen sehr ähnlich; Perl weiß jedoch, dass es sich um eine Regex handelt, und verhält sich in manchen Aspekten leicht unterschiedlich. Bei dieser Sonderbehandlung von Regex-Literalen gibt es spezielle Methoden zum Aufbau eines regulären Ausdrucks.

Zum Beispiel werden in einem Regex-Literal Variablen interpoliert. Wenn die Variable $num den Wert 20 hat, wird aus dem Regex-Literal m/:.{$num}:/ der reguläre Ausdruck ˹:.{20}:˼. Auf diese Weise kann man reguläre Ausdrücke aus Untereinheiten aufbauen. Eine andere Möglichkeit ist das Verwandeln von Groß- in Kleinbuchstaben und umgekehrt. Mit \U...\E etwa wird die Regex in Großbuchstaben verwandelt. Aus m/abc\Uxyz\E/ wird so die Regex ˹abcXYZ˼. Das ist natürlich ein dummes Beispiel, weil jeder direkt ˹abcXYZ˼ schreiben würde; interessant wird es erst in Kombination mit interpolierten Variablen. Wenn die Variable $tag den Wert »title« hat, ergibt sich aus m{</\U$tag\E>} die Regex ˹</TITLE.

Was ist das Gegenstück zu einem Regex-Literal? Man kann für den Regex-Operanden auch einen String (oder irgendeinen Perl-Ausdruck) angeben, zum Beispiel:

$MatchFeld = "^Subject:"; # Normale String-Zuweisung
   .
   . 
   .
if ($text =~ $MatchFeld) {
   .
   . 
   .

Wenn $MatchFeld als Operand von =~ benutzt wird, wird dessen Inhalt als regulärer Ausdruck interpretiert, und zwar als wirkliche Regex, nicht als Regex-Literal. Das bedeutet, dass keine Variablen interpoliert werden und \Q...\E nicht unterstützt wird.

Interessanter wird es, wenn wir

$text =~ $MatchFeld

durch

$text =~ m/$MatchFeld/

ersetzen. Das Resultat ist exakt dasselbe. In diesem Fall haben wir ein Regex-Literal, aber es besteht nur aus einem einzigen Element, nämlich dem interpolierten Wert von $MatchFeld. Dieser Inhalt einer Variablen aus einem Regex-Literal wird nicht ein zweites Mal als Regex-Literal behandelt, also werden Dinge wie \U...\E und $var im interpolierten Wert nicht gesondert behandelt. (Bei Wie Regex-Literale geparst werden finden Sie die exakten Details, wie Regex-Literale verarbeitet werden.)

Wenn ein regulärer Ausdruck in einem Programm mehrfach verwendet wird, spielt es in Bezug auf die Effizienz eine entscheidende Rolle, ob reguläre Ausdrücke als Strings oder als Regex-Literale eingegeben werden. Diese Aspekte werden ab Regex-Kompilierung, der /o-Modifikator, qr/.../ und Effizienz besprochen.

Eigenschaften von Regex-Literalen

Bei Regex-Literalen werden die folgenden Features unterstützt:

Interpolation von Variablen

Variablen, die mit $ oder @ beginnen, werden durch ihre Werte ersetzt, sie werden interpoliert. Bei Variablen mit $ wird einfach der skalare Wert eingefügt. Bei @ werden die Elemente eines Arrays oder eines Array-Slices eingefügt, durch Leerzeichen getrennt (genauer: durch den Wert der Variablen $", und das ist per Voreinstellung ein Leerzeichen). In Perl ist ›%‹ das Erkennungszeichen für einen Hash, aber es ist nicht intuitiv klar, wie ein Hash in einen String oder in eine Regex eingesetzt werden sollte, deshalb werden Hashes nicht interpoliert.

Namen für Unicode-Zeichen

Wenn Sie in Ihrem Programm »use charnames ':full';« angeben, können Sie Unicode-Zeichen mit der Notation \N{Name} mit vollem Namen angeben. Zum Beispiel entspricht \N{LATIN SMALL LETTER SHARP S} dem »ß«. In der Datei UnicodeData.txt im Verzeichnis unicore der Perl-Installation sind alle Namen aufgeführt, die Perl versteht. Den vollständigen Pfadnamen dieser Datei kann man mit dem folgenden Programmstückchen ausgeben:

use Config;
print "$Config{privlib}/unicore/UnicodeData.txt\n";

Man vergisst das »use charnames ':full';« nur zu leicht – oder auch den Doppelpunkt vor »full«; dann funktionieren die \N{...}-Sequenzen nicht. \N{...} funktioniert außerdem nicht bei überladenen Regex-Literalen, die etwas weiter unten behandelt werden.

Nächstes Zeichen in Klein- oder Großbuchstaben verwandeln

Mit \l und \u wird das darauf folgende Zeichen als Klein- bzw. Großbuchstabe interpretiert (\l für lowercase, Kleinbuchstabe; \u für uppercase, Großbuchstabe). Diese Sequenzen werden in aller Regel direkt vor einer Variablen benutzt. Wenn die Variable $title beispielsweise den Wert »mr.« hat, wird mit m/...\u$title.../ daraus die Regex ˹...Mr....˼. Die Perl-Funktionen lcfirst() und ucfirst() erledigen das Gleiche.

Bereiche in Klein- oder Großbuchstaben verwandeln

Mit den Sequenzen \L und \U wird alles bis zum Ende des Regex-Literals oder bis zu einem \E in Klein- bzw. Großbuchstaben verwandelt. Beispielsweise wird aus dem $title von vorhin mit dem Regex-Literal m/...\U$title\E.../ der reguläre Ausdruck ˹...MR....˼. Die Sequenzen entsprechen den Perl-Funktionen lc() und uc().

Man kann die Sequenzen für einzelne Zeichen und für Bereiche kombinieren: Der Code m/...\L\u$title\E.../ ergibt ˹...Mr...˼., ganz egal, wie die Groß- und Kleinschreibung vorher aussah.

Bereich als literalen String interpretieren 

Nach der Sequenz \Q werden alle Regex-Metazeichen mit einem Backslash geschützt (Q für »quoted«), und zwar bis zum Ende des Strings oder bis zu einem \E. Nur Regex-Metazeichen werden geschützt, nicht aber die Zeichen mit einer Sonderbedeutung für Regex-Literale wie die Variableninterpolation, \U, oder natürlich \E selbst. Merkwürdigerweise werden literale Backslashes, die zu einer unbekannten Backslash-Sequenz wie \F oder \H gehören, nicht geschützt; sie ergeben die Warnung »Unrecognized escape \F passed through«.

In der praktischen Anwendung ist das aber kaum ein Nachteil, weil \Q...\E im Allgemeinen für interpolierten Text benutzt wird, und da werden völlig korrekt alle Metazeichen unschädlich gemacht. Wenn zum Beispiel die Variable $title den String »Mr.« enthält, wird mit m/...\Q$title\E... daraus die Regex ˹...Mr\....˼. So sucht man nach dem String in $title, nicht nach der Regex in $title.

Das ist besonders dann sehr willkommen, wenn in der Regex nach Strings gesucht werden soll, die der Benutzer eingibt. Mit m/\Q$BenutzerEingabe\E/i sucht man ohne Beachtung der Groß- und Kleinschreibung nach den Zeichen (also nach dem String, nicht nach der Regex), die der Benutzer eingegeben hat. Die Perl-Funktion quotemeta() erfüllt den gleichen Zweck wie \Q...\E in einem Regex-Literal.

Overloading 

Mit Regex-Overloading kann man die literalen Teile einer Regex vor dem Matching in beliebiger Weise vorverarbeiten. Das Feature ist interessant, hat aber in der gegenwärtigen Implementation seine Grenzen. Unter Überladen von Regex-Literalen wird das Overloading genauer beschrieben.

Begrenzungszeichen für den Regex-Operanden

Einer der wunderlichsten Aspekte der Syntax von Perl ist, dass man die Begrenzungszeichen für die Regex-Literale frei wählen kann. Normalerweise benutzt man den Schrägstrich m/.../, s/.../.../ oder qr/.../, aber man kann so ziemlich jedes Zeichen außer alphanumerischen Zeichen und Whitespace nehmen. Man sieht nicht selten Folgendes:

m!...!      m{...}
m,...,      m<...>
s|...|...|  m[...]
qr#...#     m(...)
  • Die vier Fälle auf der rechten Seite verhalten sich besonders: Die vier Spezialfälle m(...), m{...}, m[...] und m<...> haben klammerartige, gepaarte Begrenzer; diese können verschachtelt benutzt werden, sofern die Anzahl der öffnenden Begrenzer mit der der schließenden übereinstimmt. Weil runde und eckige Klammern in regulären Ausdrücken selbst häufig vorkommen, sind m(...) und m[...] nicht besonders attraktiv; die anderen schon. Zusammen mit dem /x-Modifikator sind Formatierungen wie die folgende möglich:
m{
    Regex  # Kommentare
    hier   # hier
}x;

Wenn diese klammerartigen Begrenzer für die Regex bei einer Substitution verwendet werden, müssen auch für den Ersatztext zwei Begrenzungszeichen (die gleichen klammerartigen Zeichen oder auch andere) verwendet werden. Beispiele:

s{...}{...}
s{...}!...!
s<...>(...)
s[...]/.../

In diesem Fall darf zwischen den zwei Begrenzungszeichen-Paaren Whitespace vorkommen. Mehr zum Ersatztext beim Substitutionsoperator finden Sie bei Der Ersatztext-Operand.

  • Mit Fragezeichen als Begrenzern verhält sich der Match-Operator sehr speziell (weitere Treffer werden verhindert). Diese Funktionalität wird allerdings sehr selten benutzt (siehe Spezielle »Nur Einmal«-Mustersuche mit ?...?).
  • Wie weiter oben erwähnt wurde, wird ein Regex-Literal ähnlich wie ein String in Anführungszeichen geparst, aber immer im Hinblick auf die Verwendung des Strings als Regex. Wenn das Hochkomma als Begrenzungszeichen benutzt wird, wird diese String-Behandlung verhindert. Mit m'...' werden Variablen nicht interpoliert, und die Sequenzen zur Veränderung von String-Literalen (wie \Q...\E) sowie das \N{...}-Konstrukt funktionieren auch nicht. m'...' könnte beispielsweise bei einer Regex mit einer ganzen Anzahl von @ hilfreich sein.

Beim Match-Operator kann das führende m weggelassen werden, wenn das Begrenzungszeichen ein Schrägstrich oder ein Fragezeichen ist. Die zwei Zeilen

$text =~ m/.../;
$text =~  /.../;

sind also identisch. Ich gebe das m immer explizit an.

  

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