Verschiedene Einsatzmöglichkeiten des Match-Operators

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

Man kann den Match-Operator zwar auch als einfachen Test für »passt«/»passt nicht« einsetzen, aber man kann auch weitere Informationen über das Resultat der Mustersuche herausholen und Match-Operatoren miteinander verknüpfen. Wie sich der Match-Operator verhält, hängt in erster Linie vom Kontext ab (siehe Kontext bei Ausdrücken) und außerdem von der Verwendung des /g-Modifikators.

»Passt das?« – Skalarer Kontext ohne /g

Im skalaren Kontext, zum Beispiel in der Bedingung einer if-Anweisung, liefert der Match-Operator ein einfaches »wahr« oder »falsch«:

if ($suchtext =~ m/.../) {
    # Code für den Treffer-Fall,
    .
    . 
    .
} else {
    # Code für den Fall, dass kein Treffer erzielt wird.
    . 
    . 
    .
}

Man kann dieses boolesche Resultat auch einer Variablen zuweisen und es später testen:

my $gefunden = $suchtext =~ m/.../;
  .
  . 
  .
if ($gefunden) {
  .
  . 
  .
}

Daten aus dem Suchstring herauspflücken – Listenkontext ohne /g

Der Match-Operator wird normalerweise im Listenkontext ohne den /g-Modifikator benutzt, wenn man Daten aus dem Suchstring extrahieren will. Der Rückgabewert ist in diesem Fall die Liste der lokalen Treffer, die von den einfangenden Klammerausdrücken in der Regex erkannt wurde. So würde man beispielsweise die Zahlen für Jahr, Monat und Tag wie folgt aus einem String der Art 69/8/31 herausholen:

my ($jahr, $monat, $tag) = $datum =~ m{^ (\d+) / (\d+) / (\d+) $}x;

Die drei gefundenen Zahlen sind jetzt in den drei Variablen verfügbar (außerdem in $1, $2 und $3). Der Rückgabewert hat ein Element für jedes einfangende Klammerpaar oder die leere Liste, wenn kein Treffer erzielt wird.

Es kann natürlich sein, dass ein Klammerpaar gar keinen Anteil am Treffer hat, wie zwingend bei m/(klipp)|(klar)/ – in diesem Fall wird für das nicht passende Klammerpaar trotzdem ein Listenelement zurückgegeben: eines mit dem undefinierten Wert. Wenn in der Regex keine Klammern vorkommen, wird im Erfolgsfall die Liste (1) zurückgegeben, bei einem Fehlschlag die leere Liste.

Ein Listenkontext kann auf verschiedene Weise erzeugt werden, zum Beispiel mit einer Zuweisung an eine Array-Variable:

my @teile  =  $text =~ m/^(\d+)-(\d+)-(\d+)$/;

Wenn man nur am Text aus der ersten Klammer interessiert ist, genügte an sich ein Skalar. Dennoch muss ein Listenkontext erzwungen werden, sonst wird nur der Wahrheitswert Erfolg/Fehlschlag abgespeichert. Man vergleiche:

my ($wort)    =  $text =~ m/(\w+)/;
my $gefunden  =  $text =~ m/(\w+)/;

Die Klammern um die Variable im ersten Fall weisen das my an, für die Zuweisung (und damit auch für die Mustersuche) einen Listenkontext zu erzeugen. Im zweiten Fall wird ein skalarer Kontext vorgegeben, und $gefunden erhält nur den booleschen Rückgabewert.

Das nächste Beispiel zeigt eine gängige Formulierung:

if ( my ($jahr, $monat, $tag) = $datum =~ m{^ (\d+) / (\d+) / (\d+) $}x ) {
    # Code für den Treffer-Fall: $jahr usw. sind verfügbar.
} else {
    # Code für den Fall, dass kein Treffer erzielt wird.
}

Der Match-Operator wird in einem Listenkontext benutzt (durch die Klammer in ›my (...) =‹ erzwungen). Wenn die Mustersuche erfolgreich ist, wird daher die Liste der Variablen $1, $2 usw. zurückgegeben. Da der ganze Ausdruck aber im Bedingungsteil einer if-Anweisung steht, muss Perl diese Liste in einen skalaren Wert umbiegen. Der skalare Wert einer Liste ist einfach die Anzahl der Elemente. Diese ist positiv (und damit »wahr«), wenn ein Treffer gefunden wurde, und praktischerweise null bei einem Fehlschlag.

Alle Treffer herauspflücken – Listenkontext mit dem /g-Modifikator

Bei diesem praktischen Konstrukt ist der Rückgabewert nicht nur die Liste der Texte, die von den einfangenden Klammern erkannt wurden, sondern die Liste all solcher Texte im String, die über alle Iterationen des /g gefunden werden. Wenn in der Regex keine Klammern vorhanden sind, wird die Liste aller Gesamttreffer zurückgegeben.

Dieses einfache Beispiel extrahiert alle in einem String vorkommenden natürlichen Zahlen:

my @nums  =  $text =~ m/\d+/g;

Wenn $text eine IP-Adresse der Art ›64.156.215.240‹ enthält, bekommt @nums die vier Elemente ›64‹, ›156‹, ›215‹ und ›240‹. Zusammen mit anderen Sprachelementen kann man so eine IP-Adresse auf einfache Weise als achtstellige Hexadezimalzahl wie ›409cd7f0‹ ausgeben, was z.B. in einer Logdatei Platz spart:

my $hex_ip = join '', map { sprintf("%02x", $_) } $ip =~ m/\d+/g;

Mit einem ganz ähnlichen Vorgehen kann man die IP-Adresse zurückgewinnen:

my $ip = join '.', map { hex($_) } $hex_ip =~ m/../g

Zum Herauspflücken von Zahlen mit Dezimalstellen könnte man Folgendes verwenden:

my @nums  =  $text =~ m/\d+(?:\.\d+)?|\.\d+/g;

Es ist hierbei sehr wichtig, dass nicht-einfangende Klammern verwendet werden. Bei normalen, einfangenden Klammern werden andere Daten zurückgegeben. Manchmal ist aber genau das interessant, wie in diesem Fall:

my @Tags  =  $Html =~ m/<(\w+)/g;

Das Array @Tags erhält hier die Liste aller HTML-Tags in der Reihenfolge, wie sie im String $Html vorkommen – vorausgesetzt, dass ›<‹-Zeichen nur als Teil von HTML-Tags vorkommen.

Das geht auch mit mehreren einfangenden Klammerpaaren. Im folgenden Beispiel liegt der gesamte Inhalt einer Alias-Datei, wie sie bei Unix-Mail-Programmen üblich sind, in einem einzigen String vor. Die logischen Zeilen in diesem String sehen etwa so aus:

alias  Jeff      jfriedl@regex.info
alias  Perlbug   perl5-porters@perl.org
alias  king      elvis@tabloid.org

Mit einem regulären Ausdruck wie m/^alias\s+(\S+)\s+(.+)/m (ohne /g) werden ein Alias und die zugehörige Adresse erkannt. In einem Listenkontext gibt der Match-Operator eine Liste mit zwei Elementen zurück, beispielsweise ('Jeff', 'jfriedl@regex.info'). Mit /g erhalten wir alle diese Paare, also eine Liste der Art:

( 'Jeff', 'jfriedl@regex.info', 'Perlbug', 'perl5-porters@perl.org', 'king', 'elvis@tabloid.org' )

In diesem Fall besteht die Liste aus Schlüssel-Wert-Paaren, die man direkt einem assoziativen Array zuweisen kann. Nach

my %alias  =  $text =~ m/^alias\s+(\S+)\s+(.+)/mg;

enthält $alias{Jeff} die volle Adresse von ›Jeff‹.

  

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