Was bedeutet $ wirklich?

Inhalt:

Dies ist ein Template für den FAQ-Unterbereich RegulaereAusdrueckeEndOfString.

Einleitung

Reguläre Ausdrücke in traditionellen Anwendungen (grep, sed, vi, ...) werden meist auf Zeilen angewendet. Daher gibt es traditionell kaum einen Unterschied zwischen "Ende der Zeile" und "Ende des Strings", und die Newlines zwischen den Zeilen stehen dabei außerhalb des Wirkungsbereichs der regulären Ausdrücke.

In Perl ist das alles etwas komplizierter. Viele sind sich darüber jedoch nicht im Klaren. Daher kommt auch die weitverbreitete Annahme, dass $ in einem regulären Ausdruck auf das Ende des Strings matcht.

$ in Perl

In Wirklichkeit matcht $ in Perl in zwei Fällen:
  • Auf das Ende des Strings
  • Auf die Stelle (also den leeren String) direkt vor einem Newline, das am Ende des Strings steht

Man kann sich dies in einem Beispiel deutlich machen:
"hallo\n" =~ m/($)\n$/ and print "Match!";
Hier matcht $ zwei Mal in demselben String an unterschiedlichen Stellen: Einmal vor dem Newline und einmal danach. Um das alles noch komplizierter zu machen, sind die runden Klammern notwendig, damit $\ nicht als Variable geparst wird.

Ein anderes lustiges Beispiel:
print "Match!\n" while "\n\n\n\n\n\n\n\n" =~ m/$/g;
Hier wird "$" in einem String aus acht Newlines gesucht, und es gibt genau zwei Matches, naemlich eines vor dem letzten der acht Newlines, und eines danach. Daher sieht man in der Ausgabe zwei Mal "Match!".

Meiner (betterworlds) Meinung nach ist dies ein ziemlich dummes "Feature" von Perl, denn es gibt weitaus weniger Fälle, wo es wirklich nützlich ist, als es Fälle gibt, wo Leute sich nicht darüber im Klaren sind, was ihr Regex wirklich tut.

OK, aber ich will wirklich nur das Ende des Strings

Mit \z kann man das Ende des Strings matchen, und nur das Ende des Strings. \z tut das, was $ nach der Vorstellung einiger Anfänger und Fortgeschrittenen tut. Achtung: \Z (großes Z) tut dasselbe wie $ (jedenfalls ohne /m).

Der Anfang des Strings

^ kann benutzt werden, um den Anfang des Strings zu matchen. Hierbei gibt es keine Probleme mit Newlines. Wenn jedoch /m aktiv ist (siehe unten), muss man \A verwenden, um den Anfang zu matchen. Wenn man einheitlich sein möchte, kann man \A auch ohne /m verwenden; in dem Fall tut es dasselbe wie ^.

Sicherheitsaspekt

Die Kenntnis über den Unterschied zwischen $ und \z kann essentiell für die Sicherheit einer Perl-Anwendung sein. Oft werden reguläre Ausdrücke zur Validierung von Benutzereingaben benutzt. Wenn ich zum Beispiel einen neuen Benutzer anlegen möchte und ihn in /etc/passwd eintragen möchte, sollte ich sicherstellen, dass er keine Sonderzeichen enthält, die in dieser Datei stören würden:
    $username =~ /^[a-z]+\z/ or die "Illegal user name.\n";
Wenn ich hier $ statt \z benutzt hätte, würde man mein Script dazu bringen können, ein Newline in /etc/passwd einzufügen, womit die Benutzerdatenbank ziemlich korrupiert wäre.

Das Ende der Zeile

Um es noch komplizierter zu machen, kann man die Bedeutung von $ mit dem Flag /m verändern. Wenn dieses Flag angewandt wird, matcht $ in den folgenden Fällen:
  • Auf das Ende des Strings
  • Auf die Stelle (also den leeren String) direkt vor einem Newline (egal wo es steht)

Auch dies kann man sich mit einem Beispiel vertraut machen:
"hallo\nwelt\n" =~ m/hallo($)\nwelt($)\n$/m and print "Treffer!";

Hierzu beachte man nicht perldoc perlre (aus 5.8.8):
    m   Treat string as multiple lines.  That is, change "^" and "$" from
        matching the start or end of the string to matching the start or
        end of any line anywhere within the string.

(Und weiter unten:)

    You may, however, wish to treat a string as a
    multi-line buffer, such that the "^" will match after any newline
    within the string, and "$" will match before any newline.
Dies ist irreführend. Erstens ist "end of the string" nicht korrekt (siehe oben), zweitens ist "before any newline" nicht ausreichend, da zusätzlich wie beschrieben auch noch das Ende des Strings gematcht wird.

ChristophBussenius - 12. 4. 2008

UtilFaqSubForm edit

Titel Was bedeutet $ wirklich?
Autor
Bereich FaqRegulaereAusdruecke
Tags
Topic revision: r3 - 2010-03-19 - 01:22:22 - ChristophBussenius
 
Bitte die NutzungsBedingungen beachten.
Bei Vorschlägen, Anfragen oder Problemen mit dem PerlCommunityWiki bitten wir um WebBottomBarExample">Rückmeldung.