Blog

Eine kleine Änderung beim Pattern-Matching

12.07.2023 // Renée Bäcker

In jedem stabilen Release gibt es auch eher unscheinbare Änderungen, die auf den ersten Blick vielleicht nicht erwähnenswert erscheinen. Auf den zweiten Blick sind sie aber meist wirklich nützlich. Eine solche kleine Änderung gibt es im Bereich der regulären Ausdrücke. Die Variable ${^LAST_SUCCESSFUL_PATTERN} wurde eingeführt.

Wer kennt leere reguläre Ausdrücke und weiß, was sie tun? Kurzes Quiz: Was ist die Ausgabe von:

use feature 'say';

my $string = 'Hello';
$string =~ m{.ll};
$string =~ m{abc};

for my $check ( qw/all abc/ ) {
    say "$check: yes" if $check =~ m{};
}

Die Auflösung kommt gleich, also nicht gleich spicken, sondern überlegen. Folgende Antwortmöglichkeiten gebe ich zur Auswahl:

  1. Es gibt gar keine Ausgabe
  2. all: yes abc: yes 3. all: yes 4. abc: yes

Der leere reguläre Ausdruck ist ein Spezialfall (außer bei split //, $string). Wird der leere reguläre Ausdruck verwendet, wird der letzte erfolgreiche Match betrachtet und das Muster von dem Match genutzt.

Gehen wir das der Reihe nach durch.

  1. Die Variable $string bekommt den String Hello zugewiesen
  2. Der reguläre Ausdruck .ll matcht (das ell)
  3. Der reguläre Ausdruck abc matcht nicht.

Der letzte erfolgreiche Match ist also die Prüfung auf .ll. Damit wird bei dem leeren regulären Ausdruck genau dieses Muster genutzt. Und von den beiden Strings, die in der Schleife geprüft werden, matcht das Muster nur bei all. Also ist die Ausgabe:

all: yes

Man kann sich vorstellen, dass es nicht allzu viel Spaß macht, so einen Code zu debuggen. Man muss den Code durchgehen, prüfen welche regulären Ausdrücke so verwendet werden und wie die Eingabedaten aussehen, um dann irgendwie nachzuvollziehen, welcher Match tatsächlich erfolgreich war.

Mit der neuen Variablen ${^LAST_SUCCESSFUL_PATTERN} wird das Debugging einfacher. Wenn die Schleife so aussieht:

for my $check ( qw/all abc/ ) {
    say "$check: yes (${^LAST_SUCCESSFUL_PATTERN})" 
       if $check =~ m{};
}

dann sieht die Ausgabe wie folgt aus:

all: yes ((?^:.ll))

Damit lässt sich viel schneller der Match finden, der zuletzt erfolgreich war.


Eine weitere Variation der Schleife:

for my $check ( qw/all abc/ ) {
    my $new = $check =~ s//Perl-Academy/r;
    say $new;
}

Hier wird der leere reguläre Ausdruck in einer Ersetzung genutzt. Wer weiß, wie der leere reguläre Ausdruck funktioniert, wird auch wissen, was die Ausgabe ist. Richtig, die Ausgabe ist:

Perl-Academy
abc

Auch hier hilft die Verwendung der neuen Variable dabei, besser wartbaren Code zu schreiben. Hier wird ganz ausdrücklich gesagt, dass das Muster des letzten erfolgreichen Matches genutzt wird (die Suche nach diesem Match kann weiterhin viel Spaß bedeuten).

for my $check ( qw/ all abc/ ) {
    my $new = $check =~ s/${^LAST_SUCCESSFUL_PATTERN}/Perl-Academy/r;
    say $new;
}



Permalink: