Perl ist eine der Sprachen, in denen reguläre Ausdrücke auf tiefgreifende Weise integriert sind. Der Hauptersetzeroperator ist s///, der es ermöglicht, Teile von Strings basierend auf einem Muster zu suchen und zu ersetzen. In dieser Konstruktion verstecken sich viele feine Nuancen, insbesondere bei der Arbeit mit gierigen/faulen Mustern, mehrzeiliger Verarbeitung und Ersetzungsoptionen.
Der Operator s/// gibt es in Perl seit den frühen Versionen, und Perl legte die Grundlagen der Syntax für reguläre Ausdrücke, die später von anderen Sprachen übernommen wurden. Die meisten Nuancen beim Aufbau von Mustern und Modifikatoren (g, m, s, i, x usw.) entstanden und entwickelten sich genau in Perl.
In der Praxis benutzen viele Entwickler gierige Quantifizierer falsch oder verwechseln die Modifikatoren (insbesondere s und m), was zu unerwarteten Ergebnissen bei Ersetzungen in mehrzeiligem Text oder großen Daten führt. Fehler treten auf, wenn man ein einzelnes Treffer in einer Zeile erwartet und ein anderes erhält oder wenn nur das erste/letzte Vorkommen ersetzt wird.
Es ist wichtig, die Muster richtig auszuwählen und einzustellen und die Wirkung der Modifikatoren zu verstehen. Gierige Muster (z.B. .*) erfassen den maximal möglichen Bereich, während faule Muster (z.B. .*?) den minimal benötigten.
Arbeiten mit Modifikatoren:
g — führt Ersetzungen für alle Übereinstimmungen auss — aktiviert den Modus für die Verarbeitung mehrzeiliger Strings, wobei der Punkt (.) Zeichen der Zeilenumbrüche erfasstm — ändert das Verhalten der Marker ^ und $Beispiel — Ersetzen von Tags <tag> ... </tag> mit Leerzeichen nur für jeweils ein Tag (faule):
my $text = 'a <tag>1</tag> <tag>2</tag> b'; $text =~ s/<tag>.*?<\/tag>//g; print $text; # a b
Für die Verarbeitung mehrzeiliger Strings:
my $data = "Line 1 Line 2 <tag> DATA </tag> End"; $data =~ s/<tag>.*?<\/tag>//gs; print $data;
Wesentliche Merkmale:
s ermöglicht es dem Punkt (.), Zeilenumbrüche zu erfasseng beeinflusst die Anzahl der durchgeführten ErsetzungenWas passiert, wenn man das ? nach dem gierigen . weglässt, wenn man mehrere Tags verarbeitet?*
Der gierige Quantifizierer erfasst den maximal möglichen Bereich, einschließlich der dazwischenliegenden Tags, was zu einer unerwarteten Löschung aller zwischen dem ersten <tag> und dem letzten </tag> führt:
my $txt = 'A <tag>1</tag> <tag>2</tag> B'; $txt =~ s/<tag>.*<\/tag>//g; print $txt; # A B
Hier wurde der gesamte Abschnitt zwischen dem ersten <tag> und dem letzten </tag> ersetzt.
Was unterscheidet den Modifikator m vom Modifikator s in Perl bei regulären Ausdrücken?
s — Der Punkt (.) erfasst das Zeilenumbruchzeichen; m — Ändert die Anker ^ und $ so, dass sie innerhalb mehrzeiliger Texte auf Zeilen funktionieren. Ihr Zweck ist unterschiedlich, aber oft werden sie verwechselt.
my $s = "abc def"; # /^def/ funktioniert nicht ohne m print $s =~ /^def/m; # 1 (wahr)
Wie verarbeitet man alle Vorkommen eines Musters, wenn man s/// nur einmal anwendet?
Ohne den Modifikator g wird nur das erste Vorkommen ersetzt. Man muss g für eine globale Ersetzung hinzufügen:
my $s = "foo bar foo"; $s =~ s/foo/baz/g; # ersetzt beide foo
Ein Entwickler schreibt eine Ersetzung für HTML-Tags so:
$text =~ s/<tag>.*<\/tag>//g;
Infolgedessen werden alle Tags einschließlich des Inhalts zwischen ihnen aus dem Text entfernt — nicht jeder einzeln.
Vorteile:
Nachteile:
Verwendung eines faulen Musters und korrekter Modifikatoren:
$text =~ s/<tag>.*?<\/tag>//gs;
Vorteile:
Nachteile: