Regexes und Rules
Perl 5-Regex
Aus Gründen der Rückwärtskompatibilität sind Perl 5-"Regular Expressions", kurz regexes, immer noch vorhanden, allerdings hat sich die Schreibweise für die Modifier ein wenig verändert:
# bisher: $str =~ m/^foo\d{3}$/i; # jetzt: $str ~~ m:P5:i/^foo\d{3}$/;
Modifier werden also am Anfang geschrieben, aus =~
wird der Smart Match Operator ~~. Die
"Innereien" der regex bleiben größtenteils unverändert, nur dass aus
$0 jetzt $1 geworden ist (usw), da der
Programmname in $*PROGRAM_NAME verfübar ist und nicht
mehr in $0.
Rules
Rules sind der mächtigere und durchdachtere Nachfolger von regexes. Vieles hat sich geändert, aber einiges ist auch gleich geblieben:
- Jedes mit einem Backslash
\escapete Sonderzeichen steht genau für das das escapte Zeichen. - Capturing Groups stehen immer noch in runden Klammern
( ... ). - Alternativen werden immer noch durch
|getrennt. - Die Quantifier
+,*und?behalten ihre Bedeutung bei, auch die "non-greedy"-Varianten mit nachgestelltem Fragezeichen (wie+?).
Die Änderungen überwiegen bei weitem. Das hier ist nur eine kleine Zusammenstellung der Änderungen, die sicher nicht Vollständig ist.
- Alle Zahlen und Buchstaben bekommen durch ein vorgestellten Backslash eine Sonderbedeutung, alles andere verliert durch einen Backslash seine Sonderbedeutung.
- Leerzeichen, Tabs und New Lines werden per Default ignoriert (so wie unter p5 mit /x).
- Den /s-Switch (single line) gibt es nicht mehr,
^und$passen immer auf Anfang bzw. Ende des Strings,^^und$$auf logische Zeilenanfänge und -Enden (und auch Anfang/Ende des Strings. - Der Punkt
.matched jetzt jedes beliebige Zeichen, auch Zeilenende,\Nmatched alles außer dem Zeilenende. - Gruppierungen können jetzt mit einzlenen Anführungszeichen
erfolgen, d.h.
m/foo*/matched foooo, währendm/'foo'*/zu foofoofoo passt. - Analog zum "normalen" Perl 6 gibt es auch doppelte
Anführungszeichen, in denen auch interpoliert wird:
"...". - Non-Capturing Groups, früher
(?: ... )stehen jetzt in eckigen Klammern[ ... ]. - Code in geschweiften Klammern wird als sog.
Capture ausgeführt:
m/(\S+) { say "Text gefunden"; push @text_chunks, $0 }/. Nach einer Closure werden$0etc. zurückgesetzt. - Variablen in Regexes werden per Default nicht mehr als Regex,
sonder also String interpoliert, d.h.
my $f = "."; $text ~~ m/$f/passt nicht mehr auf beliebige Zeichen, sondern auf den Punkt. Interpolation geht noch mit<$re>. - Wenn man ein Array in eine Regex einsetzt, werden die
Elemente als Alternativen angesehen, d.h.
m/@cmd/ist äquivalent zum/ [ @cmd[0] | @cmd[1] | ... ].
< ... > ist magisch
Teile von Regexes, die in spitze Klammern < ...
> eingeschlossen sind, können sehr verschiedene
Dinge bedeuten, je nach dem, was das erste Zeichen ist - und der
Rest...
Wenn direkt innerhalb der spitzen Klammern eckige Klammern stehen,
steht das für eine Klasse von Zeiche, so wie früher
[...] (nur dass jetzt Leerzeichen ignoriert werden):
regex buchstabe { <[a..z A..Z]> };
Wenn einfach nur Buchstaben und Ziffern darin stehen, wird das Konstrukt als unter-Regex interpretiert. Damit kann man regexes verschachteln:
regex buchstabe { <[a-zA-Z]> }; regex zahl { <[0-9]> }; regex identifier { <buchstabe> [ <buchstabe> | <zahl> ]* }; regex sigil { <[$@%]> }; regex p5_var { <sigil> <identifier>};
Es gibt auch schon fertige Regexes, so steht
<alpha> für Buchstaben, <sp> für
das Leerzeichen und <ws> für ein "magisches"
Leerzeichen, d.h. für \s+ zwischen alphanumerischen
Zeichen und für \s* sonst.
Auch den von uns gerade definierten identifier gibt es als
<ident> vorgefertigt.
Fängt das Konstrukt mit <?{ an, so wird das als
Assertion, also Bedingung gewertet. Folgende Regex matched ein- bis
dreistellige Zahlen von 0 bis 255:
regex byte { (\d**{1..3}) <?{ $0 < 256 }> };
Das Match-Objekt
Wenn man eine Regex mit dem Smart Match Operator ~~
auf einen String los lässt, ist das Ergebnis ein Match-Objekt:
my $match = "foo123" ~~ m/ <ident> /; # wenn man es nicht zuweist wird es in $/ gespeichert. # wie sieht diese Magie aus? say $match.perl; # liefert: Match.new( ok => Bool::True, from => 0, to => 6, str => "foo123", sub_pos => (), sub_named => { "ident" => Match.new( ok => Bool::True, from => 0, to => 6, str => "foo123", sub_pos => (), sub_named => {} ) } ) # im Boolean-Kontext: if $match { say "Identifier found"; } # im String-Kontext liefert es den gematchen String: print ~$match; # spuckt "foo123" aus # Die Position, an der ein Treffer gefunden wurde: $match.from .. $match.to;
Ist das magisch? Es kommt sogar noch besser: Wenn man Capturing
Groups ( ... ) in der regex hat, kann man das
Match-Objekt als Array verwenden, das die verschiedenen Captures als
Elemente enthält:
my $m = "bar" ~~ m/(.) a (r)/; say $m[0]; # ist 'b' say $m[1]; # ist 'r'
Und wenn man ein capture in spitzen Klammern, z.B.
<ident> verwendet hat, kann man das Match-Objekt
als Hash benutzen, und auf die Captures mit ihrem Namen zugreifen:
regex sigil { '@' | '$' | '%' }; my $m = ' $foo bar' ~~ m/ <sigil> <ident>/; say $m<sigil>; # gibt $ say $m<ident>; # gibt foo
Text ersetzen
Die alte Form des Text-Ersetzens mit s/// geht auch
unter Perl 6, neue Formen sind dazu gekommen:
my $s1 = "klein"; $s1 tr ~~ s/^kl/k/; # $s1 tr eq "kein" # oder: $s.subst(m/^kl/, "k"); #neu (entspricht dem p5 /e Flag): my $s2 = "7 drunken nights"; $s2 ~~ s[(\d+)] = 2 * $0; # jetzt "14 drunken nights" # alle Flags kommen an den Anfang: my $s3 = "35 beers, 7 drunken nights"; $s3 ~~ s:g[(\d+)] = 2 * $0;
Man beachte im letzten Beispiel, dass das keine normale Zuweisung ist, sondern dass die rechte Seite bei jedem Match neu ausgwertet wird.