Reguläre Ausdrücke

[ vorherige Seite ] [ Titelseite ] [ Inhalt ] [ Index ] [ nächste Seite ]


Einfache Zeichensuche


Wir fangen mit dem einfachsten Beispiel an: Die Suche nach einem bestimmten Zeichen:

#!/usr/local/bin/perl -w

use strict;

my $t = "Demo-Zeichenkette";

if($t =~ /e/) { print "wahr\n" } else { print "falsch\n" }

Hier ist der reguläre Ausdruck nur der Buchstabe "e" und der Operator "=~" veranlaßt eine Suche nach diesem Zeichen in dem String $t. Diese Suche beginnt immer am Anfang einer Zeichenkette, so daß sie schon beim zweiten Zeichen erfolgreich ist (Demo-Zeichenkette); die Ausgabe des Programms ist also "wahr".

Anstelle eines Zeichens können auch beliebig viele gesetzt werden - gesucht wird dann nach dieser Folge von Zeichen:

#!/usr/local/bin/perl -w
use strict;

if("Leder"  =~ /ede/) { print "wahr\n" } else { print "falsch\n" } # Test 1
if("Eder"   =~ /ede/) { print "wahr\n" } else { print "falsch\n" } # Test 2
if("Gerade" =~ /ede/) { print "wahr\n" } else { print "falsch\n" } # Test 3

Dieses Skript liefert nur in dem ersten Test "wahr", ansonsten immer "falsch", da der reguläre Ausdruck "ede" genau passen muß. D.h., es wird hier auf Groß- und Kleinschreibung geachtet (Test 2) und der Ausdruck muß so wie er definiert ist in der Zeichenkette auftreten - es genügt nicht, daß die Buchstaben "e", "d" und "e" irgendwo im durchsuchten String stehen (Test 3).

Zu beachten ist, daß nicht nach jedem Zeichen einfach gesucht werden kann wie im obigen Beispiel, da einige in regulären Ausdrücken besondere Bedeutung haben. Es handelt sich dabei um

. ? * + ^ $ | \ ( ) [ {

sowie um das Zeichen, das als "Klammer" um den regulären Ausdruck verwendet wird (meistens der Schrägstrich "/"). Will man nach diesen Symbolen suchen, so muß man einen Backslash ("\") voranstellen:

#!/usr/local/bin/perl -w
use strict;

if("1...3"    =~ /\.\./)    { print "wahr\n" } else { print "falsch\n" } # Test 1
if("/usr/bin" =~ /\/usr\//) { print "wahr\n" } else { print "falsch\n" } # Test 2
if("/usr/bin" =~ m#/usr/#)  { print "wahr\n" } else { print "falsch\n" } # Test 3
if('??\$'     =~ /\\\$/)    { print "wahr\n" } else { print "falsch\n" } # Test 4

Diese Tests liefern alle "wahr". Wie man beim Vergleich von Test 2 und Test 3 sieht, ist es beim Testen von UNIX-Pfadnamen oft sinnvoll, die Schrägstrich-Klammerung zu ersetzen, um allzuviele Backslashes zu vermeiden. Man beachte im Test 4 noch die einfachen Anführungsstriche, die verhindern, daß im String aus \$ ein einfaches $ wird.

Für einige häufig gebrauchte Zeichen, die sich schlecht direkt darstellen lassen, gibt es besondere Symbole (siehe auch unter Stringkonstanten):

Zeichen Bedeutung
\n neue Zeile
\r Wagenrücklauf
\f Seitenvorschub
\t Tabulator
\a Signalton
\e Escape

Außerdem lassen sich auch alle Zeichen durch ihren ASCII-Code (in oktaler Darstellung) schreiben, indem man dem 3-stelligen Code einen Backslash voranstellt (so ist beispielweise "\101" äquivalent zum Buchstaben "A"). Anmerkung: es müssen immer drei Ziffern sein - also notfalls vorne mit einer oder zwei Nullen auffüllen.

Eine ganz besondere Bedeutung hat in regulären Ausdrücken der Punkt ".": er steht normalerweise für jedes beliebige Zeichen mit Ausnahme des Zeilenvorschubs "\n".

#!/usr/local/bin/perl -w

use strict;

my $t = "1.Spalte\t2.Spalte";    # mit Tabulatorzeichen \t

if($t =~ /e\t2/)  { print "wahr\n" } else { print "falsch\n" } # Test 1
if($t =~ /\t\t/)  { print "wahr\n" } else { print "falsch\n" } # Test 2
if($t =~ /p...e/) { print "wahr\n" } else { print "falsch\n" } # Test 3

Test 1 ergibt "wahr", da die Suche in der Mitte von $t erfolgreich ist. Test 2 dagegen liefert "falsch" (keine zwei aufeinanderfolgenen Tabulatoren in $t). Test 3 wiederum verläuft erfolgreich - er findet einen zum regulären Ausdruck passenden Substring (1.Spalte\t2.Spalte).

[Seitenanfang]


Zeichenklassen


Bisweilen möchte man nicht nur nach einem bestimmten Zeichen suchen (beispielsweise dem Buchstaben "a"), sondern nach einem Zeichen, das einer Gruppe angehört (z.B. nach einem "Vokal", d.h., nach einem Buchstaben aus der Menge {a,e,i,o,u}).

Eine solche Klasse kann mit Hilfe der eckigen Klammern ("[...]") definiert werden. Damit wird dann im Vorgabestring nach einem Symbol aus dieser Klasse gesucht.

#!/usr/local/bin/perl -w

use strict;

my $t = "Computer";

if($t =~ /[aeiou]/) { print "wahr\n" } else { print "falsch\n" } # Test 1
if($t =~ /[xyz]/)   { print "wahr\n" } else { print "falsch\n" } # Test 2

Hier liefert nur Test 1 "wahr" ("o" aus der Klasse "[aeiou]" in "Computer" gefunden); die zweite Suche aber schlägt fehl (weder "x" noch "y" noch "z" kommen in "Computer" vor).

Auch in Zeichenklassen muß (wie bei einfachen Symbolen in regulären Ausdrücken) darauf geachtet werden, daß einige Zeichen eine besondere Bedeutung haben:

^ - ] \ $

Benötigt man eines dieser Zeichen explizit innerhalb einer Zeichenklasse, so muß man einen Backslash voranstellen.

Hier sei speziell die Wirkung von Zirkumflex ("^") und Minuszeichen ("-") für Zeichenklassen beschrieben. Ersterer bedeutet (wenn er unmittelbar nach der öffnenden Klammer ("[") steht) soviel wie "alle Zeichen außer ...". Das Minus wird verwendet, um eine Reihe aufeinanderfolgender (im Sinne des verwendeten Zeichensatzes) Symbole abkürzend darzustellen (z.B. alle Kleinbuchstaben durch "[a-z]").

#!/usr/local/bin/perl -w

use strict;

my $t = 'Ist "1" prim ?';

if($t =~ /[0-9]/)  { print "wahr\n" } else { print "falsch\n" } # Test 1
if($t =~ /["']/)   { print "wahr\n" } else { print "falsch\n" } # Test 2
if($t =~ /[^A-Z]/) { print "wahr\n" } else { print "falsch\n" } # Test 3

Die Ausgabe ist jeweils "wahr". Im ersten Test wird die Zahl 1 als Mitglied der Klasse der Ziffern 0-9 erkannt. Test 2 ist erfolgreich beim ersten Auftreten von doppelten Anführungszeichen vor der 1 (die einfachen Anführungszeichen in der Defintion $t = ... gehören ja nicht zu $t). Im dritten Test schließlich wird das "s" in "Ist" gefunden, da es das erste Zeichen ist, das nicht zur Klasse der Großbuchstaben gehört.

Für einige oft verwendete Zeichenklassen gibt es abkürzende Schreibweisen:

Zeichen Entsprechung Bedeutung
\d [0-9] Ziffer
\D [^0-9] Gegenstück zu \d
\w [a-zA-Z_0-9] Buchstabe, Unterstrich oder Ziffer
\W [^a-zA-Z_0-9] Gegenstück zu \w
\s [ \t\n\f\r] Leerzeichen
\S [^ \t\n\f\r] Gegenstück zu \s

(zur Erinnerung: \t, \n, \f und \r stehen für Tabulator, neue Zeile, Seitenvorschub und Wagenrücklauf.)

Ein Sonderfall ist das Zeichen "\b", das innerhalb einer Klasse für einen Rückschritt (backspace) steht. Außerhalb einer Zeichenklasse besitzt "\b" aber eine völlig andere Bedeutung, wie wir später sehen werden.

Diese Abkürzungen können wiederum in Klassen verwendet werden.

#!/usr/local/bin/perl -w

use strict;

my $t = 'Eine Zahl: -3.6209';

if($t =~ /[-\d.]/) { print "wahr\n" } else { print "falsch\n" }

Die Klasse "[-\d.]" veranlaßt die Suche nach dem ersten Auftreten eines der Symbole aus der Menge {-,0,1,2,3,4,5,6,7,8,9,.} (hier wird das Minuszeichen zuerst gefunden).

Anmerkungen: Das Minuszeichen besitzt hier keine Sonderbedeutung (wie in "[a-z]"), da es am Anfang der Klasse steht. Beim Punkt kann in Zeichenklassen auf das Voranstellen eines Backslashes verzichtet werden.

Selbstverständlich können einfache Zeichensuche und Zeichenklassen in regulären Ausdrücken miteinander kombiniert werden. Beispiel: Suche nach einem Teilstring, der eine Versionsnummer beschreibt.

#!/usr/local/bin/perl -w

use strict;

my $t = 'Hier ist Perl 5.002 installiert.';

if($t =~ /Perl [1-5]\.\d\d\d/) { print "wahr\n" } else { print "falsch\n" }

[Seitenanfang]


Wiederholungen


Besonders flexibel werden reguläre Ausdrücke durch die Möglichkeit nach dem mehrfachen Auftreten von Zeichen zu suchen (wobei "mehrfach" auch "keinmal" einschließt).

Dies erfolgt im allgemeinsten Falle durch die Angabe eines Zahlenbereichs in geschweiften Klammern. So bedeutet beispielsweise "{2,5}", daß das vorangehende Symbol 2, 3, 4 oder 5-mal auftreten darf.

Ein Beispiel:

#!/usr/local/bin/perl -w

use strict;

my $t = "A----Z";

if($t =~ /-{1,3}/)  { print "wahr ($&)\n" } else { print "falsch\n" } # Test 1
if($t =~ /-{2,6}/)  { print "wahr ($&)\n" } else { print "falsch\n" } # Test 2
if($t =~ /-{5,10}/) { print "wahr ($&)\n" } else { print "falsch\n" } # Test 3

Test 1 gibt den Wert "wahr" aus. Hier ist das gefundene Muster (in der Variablen $&) von besonderem Interesse: es werden drei Minuszeichen ausgegeben. Darin erkennt man eine wichtige Eigenschaft der Suche nach mehrfachen Zeichen: Perl versucht, möglichst viele davon zu finden. Dies sehen wir auch im zweiten Test: hier wird die Maximalzahl von vier Minuszeichen als gefundener Substring ausgegeben. Dagegen liefert der Test 3 den Wert "falsch", da die Bedingung nicht einmal durch die kleinste Zahl (5) erfüllt werden kann.

Da solche Mehrfachsuchen sehr häufig in Perl benutzt werden, gibt es einige Abkürzungen, die die Schreibarbeit vereinfachen (und auch zur Übersichtlichkeit beitragen):

Abkürzung Entsprechung Bedeutung
{n} {n,n} genau n-mal
{n,}   mindestens n-mal
? {0,1} höchstens einmal
+ {1,} mindestens einmal
* {0,} beliebig oft

Beispiele:

#!/usr/local/bin/perl -w

use strict;

my $t = "xxxAzz";

if($t =~ /x{2}/)  { print "wahr ($&)\n" } else { print "falsch\n" } # Test 1
if($t =~ /x{2,}/) { print "wahr ($&)\n" } else { print "falsch\n" } # Test 2
if($t =~ /z+/)    { print "wahr ($&)\n" } else { print "falsch\n" } # Test 3
if($t =~ /B?/)    { print "wahr ($&)\n" } else { print "falsch\n" } # Test 4
if($t =~ /xAy*/)  { print "wahr ($&)\n" } else { print "falsch\n" } # Test 5
if($t =~ /x*z+/)  { print "wahr ($&)\n" } else { print "falsch\n" } # Test 6

Die Variable $t besteht alle Tests erfolgreich; die folgende Liste zeigt, an welchen Stellen jeweils der reguläre Ausdruck paßt (Perl sucht hier immer die größtmögliche Lösung):

Wie man in Test 5 sieht, bezieht sich ein Sonderzeichen zur Mehrfachsuche nur auf das direkt davor stehende Zeichen (im Beispiel also nur auf das "y"), nicht aber auf andere Symbole weiter vorne.

Wenn gesagt wird, daß Perl die größtmögliche Lösung sucht, so ist dies eigentlich nicht ganz richtig; man sollte genauer sagen: die längste Lösung, die sich bei der Suche ab dem Startpunkt des vorgegebenen Strings ergibt. Eine Suche beginnt immer vor dem ersten Zeichen der zu durchsuchenden Zeichenkette. Wird, von dieser Startposition ausgehend, eine Lösung gefunden, so wird die Suche (erfolgreich) abgebrochen, auch wenn es vielleicht weiter hinten noch eine längere Lösung gäbe. Bei einem Fehlschlag beginnt eine erneute Suche ein Zeichen weiter hinten; dieses Verfahren wiederholt sich so lange, bis eine Lösung gefunden oder das Ende des Strings erreicht wird.

#!/usr/local/bin/perl -w

use strict;

my $t = "aa==aaaa";

if($t =~ /a*/) { print "wahr ($&)\n" } else { print "falsch\n" } # Test 1
if($t =~ /=*/) { print "wahr ($&)\n" } else { print "falsch\n" } # Test 2
if($t =~ /=+/) { print "wahr ($&)\n" } else { print "falsch\n" } # Test 3

In Test 1 bietet Perl als gefundenen Substring "aa" ("aa==aaaa") an, obwohl die Lösung "aaaa" ("aa==aaaa") länger wäre. Ein scheinbar paradoxes Verhalten zeigt Test 2: hier ist die Lösung leer! Die Erklärung dafür ist, daß von der Startposition ausgehend eine Lösung gefunden wurde (0-mal "=") und dann die Suche abgebrochen wird. Test 3 schließlich gibt "==" aus, da ja hier mindestens ein "=" gefunden werden muß.

Die Problematik, daß Perl immer versucht, eine möglichst große Lösung zu finden, wurde schon angesprochen. Dies ist bisweilen unerwünscht; daher gibt es seit Perl 5 auch eine Variante, um eine möglichst kurze Lösung zu suchen. Dies geschieht, indem einfach ein Fragezeichen angehängt wird. Die entsprechenden Kombinationen sehen dann so aus:

Quantifizierer Bedeutung
{n,m}? mindestens n-mal, höchstens m-mal
{n}? genau n-mal (äquivalent zu {n})
{n,}? mindestens n-mal
?? höchstens einmal
+? mindestens einmal
*? beliebig oft

Ein Beispiel, das den Unterschied zwischen minimaler und maximaler Suche verdeutlicht:

#!/usr/local/bin/perl -w

use strict;

my $t = "mmmmm";

if($t =~ /m+/)  { print "wahr ($&)\n" } else { print "falsch\n" } # Test 1
if($t =~ /m+?/) { print "wahr ($&)\n" } else { print "falsch\n" } # Test 2
if($t =~ /m*?/) { print "wahr ($&)\n" } else { print "falsch\n" } # Test 3

Der erste Test gibt "mmmmm" als (maximale) Lösung aus, während Test 2 nur "m" (die minimale Lösung) liefert. Der dritte Test schließlich bietet als Lösung gar einen leeren String an (0-mal "m").

Es sei hier noch erwähnt, daß beispielweise "m*?" keinesfalls immer automatisch null Zeichen bedeuten muß wie man nach dem obigen Beispiel vielleicht zunächst glauben mag.

#!/usr/local/bin/perl -w

use strict;

my $t = "AmmmAmmmA";

if($t =~ /Am*?A/) { print "wahr ($&)\n" } else { print "falsch\n" } # Test 1
if($t =~ /A.+A/)  { print "wahr ($&)\n" } else { print "falsch\n" } # Test 2
if($t =~ /A.+?A/) { print "wahr ($&)\n" } else { print "falsch\n" } # Test 3

Hier enthält der gefundene Substring im Test 1 drei "m" ("AmmmAmmmA"). Lehrreich ist auch der Vergleich der beiden anderen Tests: maximale Lösung in Test 2 ("AmmmAmmmA") und minimale Lösung in Test 3 ("AmmmAmmmA").

[Seitenanfang]


Gruppierung


Im Abschnitt zur Mehrfachsuche wirkte eine entsprechende Anweisung immer nur auf das eine unmittelbar davor stehende Zeichen. Mit Hilfe von Klammern ("(...)") können auch längere Ausdrücke mehrfach gesucht werden.

Dazu ein Beispiel:

#!/usr/local/bin/perl -w

use strict;

my $t = "1.030303";

if($t =~ /03{2,3}/)   { print "wahr ($&)\n" } else { print "falsch\n" } # Test 1
if($t =~ /(03){2,3}/) { print "wahr ($&)\n" } else { print "falsch\n" } # Test 2

Test 1 liefert hier "falsch" (es wird nach einer "0" gefolgt von 2 oder 3 "3"en gesucht). Erfolgreich dagegen verläuft Test 2: er findet "030303" (längste Lösung).

Klammern bewirken auch noch einen Nebeneffekt: Derjenige Substring, der auf das Muster der ersten Klammer paßt, wird in die Variable $1 geschrieben, der zweite Substring in $2, usw. Zur Festlegung der Reihenfolge der Klammern zählt die jeweils öffnende Klammer (dies ist wichtig bei ineinander verschachtelten Klammerpaaren).

#!/usr/local/bin/perl -w

use strict;

my $t = "Breite: 7.5 m";

if($t =~ /(\w+)([\d.]+ m)/) { print "wahr ($&)\n" } else { print "falsch\n" }

print "\$1: $1\n";
print "\$2: $2\n";

Auch dieser recht kompliziert aussehende reguläre Ausdruck läßt sich einfach auflösen:

Somit enthält schließlich $1 den Wert "Breite" und $2 den Wert "7.5 m". Da alle Bedingungen der Suche erfüllt sind, ergibt sich natürlich der Gesamtwert "wahr".

Möchte man den Nebeneffekt der Zuweisung von $1, $2, $3,... verhindern, fügt man nach der öffnenden Klammer "?:" ein.

#!/usr/local/bin/perl -w

use strict;

my $t = "a b";

$t =~ /(.)\s(.)/;
print "\$1: $1\n";      # gibt 'a' aus

$t =~ /(?:.)\s(.)/;
print "\$1: $1\n";      # gibt 'b' aus

Im ersten Test werden sowohl $1 (mit "a") als auch $2 (mit "b") belegt. Im zweiten Test dagegen findet bei der ersten Klammer keine Zuweisung statt und der Inhalt der zweiten Klammer ("b") wird in $1 geschrieben.

Es ist sogar möglich, schon innerhalb des regulären Ausdrucks auf vorher im String gefundene Teilstrings zuzugreifen. So findet sich der Wert der ersten Klammer in \1, der der zweiten Klammer in \2, usw. Die Zuordnung ist identisch zu der von $1, $2, usw., allerdings dürfen die "Backslash-Variablen" nur innerhalb des Suchmusters und die "Dollar-Variablen" nur außerhalb verwendet werden.

#!/usr/local/bin/perl -w

use strict;

my $t = "abc--defg-h----ijk";

if($t =~ /(.{2}).+?\1/) { print "wahr ($&)\n" } else { print "falsch\n" }
print "\$1: $1\n";

Der reguläre Ausdruck sucht nach genau zwei gleichen Zeichen, die aber ansonsten beliebig gewählt sein können, gefolgt von einer möglichst kurzen Zeichenkette aus mindestens einem Symbol gefolgt von dem Zeichenpaar, das in der ersten Klammer gefunden wurde. Der gefundene Substring lautet dann "--defg-h--" und $1 enthält wie erwartet "--".

Die Verwendung von \1, \2, usw. kann zu Problemen führen, wenn sich daran eine Suche nach Ziffern anschließt; eine mögliche Lösung ist die Benutzung von Klammern des Typs "(?:...)":

#!/usr/local/bin/perl -w

use strict;

my $t = "12--456--12";

if($t =~ /(--)\d+?\112/)     { print "wahr ($&)\n" } else { print "falsch\n" } # Test 1
if($t =~ /(--)\d+?(?:\1)12/) { print "wahr ($&)\n" } else { print "falsch\n" } # Test 2

Hier schlägt Test 1 fehl, da "\112" als Oktal-Code interpretiert wird (Zeichen "J"). Die zusätzliche Klammer in Test 2 sorgt für die korrekte Lösung ("--456--12").

[Seitenanfang]


Alternativen


Wie man bei der Suche nach einzelnen Zeichen eine Auswahl vorgeben kann, haben wir im Abschnitt zu den Zeichenklassen gesehen. Natürlich möchte man diese Möglichkeit auch bei längeren Ausdrücken zur Verfügung haben. Dazu wird der senkrechte Strich ("|") verwendet, der die einzelnen Alternativen voneinander trennt.

#!/usr/local/bin/perl -w

use strict;

my $t = "Perl";

if($t =~ /FORTRAN|C|Pascal|Perl/) { print "wahr ($&)\n" } else { print "falsch\n" }

Bei der Suche werden die Alternativen von links beginnend durchprobiert bis ein passendes Muster gefunden wurde (hier: "Perl").

Bei komplexeren Ausdrücken müssen meist Klammern gesetzt werden, damit klar ist, welche Teile zu den Alternativen gehören und welche nicht.

#!/usr/local/bin/perl -w

use strict;

my $t = "1997";

if($t =~ /1996|97|98/)   { print "wahr ($&)\n" } else { print "falsch\n" }
if($t =~ /19(96|97|98)/) { print "wahr ($&)\n" } else { print "falsch\n" }

Beide Tests sind zwar erfolgreich, liefern aber unterschiedliche Ergebnisse in $& ("97" bzw. "1997")

[Seitenanfang]


Ankerpunkte


Ankerpunkte bieten die Möglichkeit festzulegen, daß der gesuchte Substring an einer bestimmten Stelle in der vorgegebenen Zeichenkette auftreten muß.

Soll nach einem Muster nur am Beginn eines Strings gesucht werden, so setze man einen Zirkumflex ("^") oder "\A" an den Beginn des regulären Ausdrucks. Solange die untersuchte Zeichenkette keinen Zeilenvorschub enthält verhalten sich die beiden Ankerpunkte identisch (mehr hierzu im Abschnitt zu den Optionen von regulären Ausdrücken).

Analog erfolgt die Suche am Ende eines Strings: hier sind die Symbole, die am Ende des regulären Ausdrucks stehen, das Dollar-Zeichen ("$") bzw. "\Z". Auch diese Ankerpunkte unterscheiden sich nicht in ihrer Wirkung solange keine Zeilenvorschübe vorhanden sind.

#!/usr/local/bin/perl -w

use strict;

my $t = "abrakadabra";

if($t =~ /^abra/)  { print "wahr\n" } else { print "falsch\n" } # Test 1
if($t =~ /abra$/)  { print "wahr\n" } else { print "falsch\n" } # Test 2
if($t =~ /^kada/)  { print "wahr\n" } else { print "falsch\n" } # Test 3
if($t =~ /^abra$/) { print "wahr\n" } else { print "falsch\n" } # Test 4

Test 1 findet den passenden Substring am Anfang von $t (abrakadabra), während Test 2 am Ende fündig wird (abrakadabra). Die Suche in Test 3 dagegen bleibt erfolglos; es ist zwar ein Substring "kada" vorhanden, der steht aber nicht wie gefordert am Anfang von $t. Auch Test 4 liefert "falsch"; auch wenn "abra" sowohl am Anfang als auch am Ende von $t steht, so sind dies doch zwei verschiedene Substrings.

Man beachte, daß diese Ankerpunkte gewissermaßen eine höhere Priorität besitzen als beispielsweise das Alternativ-Symbol ("|"):

#!/usr/local/bin/perl -w

use strict;

my $t = "Mein Computer";

if($t =~ /^Rechner|Computer$/)   { print "wahr\n" } else { print "falsch\n" } # Test 1
if($t =~ /^(Rechner|Computer)$/) { print "wahr\n" } else { print "falsch\n" } # Test 2

Test 1 liefert den Wert "wahr", da er "Computer" am Ende von $t findet ("Suche nach 'Rechner' am Anfang oder 'Computer' am Ende"). Test 2 dagegen gibt die Antwort "falsch", da hier der Suchauftrag lautet: "Suche nach 'Rechner' oder 'Computer', die sich von Anfang bis Ende des Strings erstrecken".

Weitere Ankerpunkte können Wortgrenzen sein. Dabei ist eine solche Grenze definiert als der Punkt zwischen einem Zeichen aus der Klasse \w und einem aus \W. Eine solche Wortgrenze wird durch "\b" dargestellt (dabei handelt es sich nicht um ein Zeichen an sich, sondern den Raum zwischen zwei Symbolen!). Das Gegenstück zu "\b" ist "\B" (Ankerpunkt inner- oder außerhalb eines Wortes).

#!/usr/local/bin/perl -w

use strict;

my $t = "Der ASCII-Code";

if($t =~ /\b[A-Z]/) { print "wahr ($&)\n" } else { print "falsch\n" } # Test 1
if($t =~ /\B[A-Z]/) { print "wahr ($&)\n" } else { print "falsch\n" } # Test 2

Im Test 1 wird nach dem ersten Großbuchstaben an einer Wortgrenze gesucht; hier wird das "D" ("Der ASCII-Code") gefunden, auch wenn es hier nicht (am Anfang des Strings) nach einem Zeichen aus \W steht, da Anfang und Ende eine entsprechende Sonderbehandlung erfahren. Test 2 dagegen sucht nach einem Großbuchstaben innerhalb eines Wortes; die Lösung lautet hier "S" ("Der ASCII-Code").

[Seitenanfang]


Umgebung eines Musters


Insbesondere bei der vorausschauenden und zurückblickenden Suche gab es im Laufe der einzelnen Perl-5-Versionen einige Erweiterungen.

Man kann damit den Erfolg einer Mustersuche davon abhängig machen, ob nicht nur das gesuchte Muster selbst paßt, sondern auch die Umgebung, d.h. die Zeichen davor und dahinter, mit berücksichtigen. So kann man etwa sagen: "Suche den Teilstring 'Regen', aber nur, wenn er nicht von 'wurm' gefolgt wird."

Folgende Klammerausdrücke stehen zur Verfügung:

Ausdruck Bedeutung Erläuterung
(?=...) positive Vorausschau nur dann erfolgreich, wenn ... folgt
(?!...) negative Vorausschau nur dann erfolgreich, wenn ... nicht folgt
(?<=...) positive Rückschau nur dann erfolgreich, wenn ... vorangeht
(?<!...) negative Rückschau nur dann erfolgreich, wenn ... nicht vorangeht
#!/usr/local/bin/perl -w

use strict;

my $t = "Bandwurm Regenwurm Regenschirm Regenschauer";

if($t =~ /Regen(?=scha)\w+/)  { print "wahr ($&)\n" } else { print "falsch\n" } # Test 1
if($t =~ /Regen(?!wurm)\w+/)  { print "wahr ($&)\n" } else { print "falsch\n" } # Test 2
if($t =~ /\w+(?<=Regen)wurm/) { print "wahr ($&)\n" } else { print "falsch\n" } # Test 3
if($t =~ /\w+(?<!Regen)wurm/) { print "wahr ($&)\n" } else { print "falsch\n" } # Test 4
wahr (Regenschauer)
wahr (Regenschirm)
wahr (Regenwurm)
wahr (Bandwurm)

Hierbei ist unbedingt zu beachten, daß der Teilstring, der zu den Ausdrücken in einer der Klammern gehört, nicht Bestandteil der Lösungsvariablen $& ist (er gehört nicht zum gefundenen Muster, sondern stellt nur eine Bedingung an die Umgebung dar). Im obigen Beispiel werden die vollständigen Wörter nur deswegen ausgegeben, weil die jeweiligen Worthälften auf das zusätzliche Muster "\w+" passen.

[Seitenanfang]


Kommentare


Um bei komplexen regulären Ausdrücken die Übersicht zu behalten, können Kommentare in Klammern wie diesen "(?#...)" eingefügt werden.

#!/usr/local/bin/perl -w

use strict;

my $t = "Wasserfall";

if($t =~ /((.)\2)(?# suche zwei gleiche Zeichen)/) {
    print "\$1: $1\n";             # gibt 'ss' aus
}

Man beachte, daß hier "\2" verwendet werden muß, um das Zeichen, das auf "." paßt, zu verwenden, da der Punkt nach der zweiten öffnenden Klammer steht.

[Seitenanfang]


[ vorherige Seite ] [ Titelseite ] [ Inhalt ] [ Index ] [ nächste Seite ]

Autor: Eike Grote Version: 2.05 (24.1.2012)