Gierig oder genügsam – der Treffer geht vor
(Auszug aus "Reguläre Ausdrücke" von Jeffrey E. F. Friedl)
Vergegenwärtigen wir uns das »Kurskorrektur«-Beispiel aus Erweiterte einführende Beispiele (siehe unter Programmbeispiel: Aktienkurse). Das Beispiel wird uns noch einige Male beschäftigen, daher kurz zusammengefasst: Wegen der nicht beliebig genauen Fließkommadarstellung kamen Werte, die »1.625« oder »3.00« lauten sollten, als »1.62500000002828« und »3.00000000028822« heraus. Zur Korrektur hatte ich mit
$kurs =~ s/(\.\d\d[1-9]?)\d*/$1/;
alle Dezimalstellen des Werts in der Variablen $kurs bis auf zwei oder drei abgeschnitten. ˹\.\d\d˼ erkennt die ersten zwei Dezimalstellen, das ˹[1-9]?˼ eine dritte nur dann, wenn sie nicht null ist.
Dazu hatte ich geschrieben:
Was bisher erkannt wurde, soll erhalten bleiben, deshalb wird es eingeklammert, so dass es in der Variablen $1 aufgefangen wird. Wir werden dieses $1 im Ersatztext verwenden. Falls der reguläre Ausdruck nur auf gerade das Bisherige passt, wird der ganze erkannte String durch genau denselben ersetzt – nicht sehr interessant. Nun hört aber unser regulärer Ausdruck nicht nach der Klammer auf. Wenn dieser Teil der Regex auch auf Zeichen im String passt, werden diese nicht in $1 abgelegt, kommen damit nicht in den Ersatzteil der Substitution und werden so gelöscht. In unserem Fall sind das alle zusätzlichen Ziffern, die auf das ˹\d*˼ am Ende der Regex passen.
Schön und gut, aber was passiert, wenn der Wert der Variablen $kurs bereits richtig ist? Wenn er 27.625 ist, dann passt ˹(\.\d\d[1-9]?)˼ auf alles vom Dezimalpunkt bis an das Ende des Strings. Das ˹\d*˼ am Ende passt auf gar nichts, und damit ersetzt die Substitution .625 durch .625 – eine Nulloperation.
Das ist zwar das gewünschte Resultat, aber wäre es nicht vielleicht besser, wenn in so einem Fall gar keine Substitution erfolgte? Nur wenn das ˹\d*˼ am Ende der Regex auf eine oder mehr Ziffern passt, muss wirklich etwas ersetzt werden. »Eine oder mehr Ziffern« – das entspricht dem Plus! Wir ersetzen einfach ˹\d*˼ durch ˹\d+˼:
$kurs =~ s/(\.\d\d[1-9]?)\d+/$1/
Mit diesen unmöglichen Zahlen wie »1.62500000002828« funktioniert das so wie vorher, aber bei bereits korrekten Zahlen wie »9.43« passt das ˹\d+˼ am Ende nicht mehr, und es erfolgt keine Substitution. Also eine gute Verbesserung, ja? Nein! Was passiert bei einer Zahl mit drei Nachkommastellen wie 27.625? Wir möchten, dass dieser Wert gar nicht verändert wird, aber das ist leider nicht, was tatsächlich geschieht. Versuchen Sie, die Arbeitsweise der Maschine bei 27.625 selbst nachzuvollziehen, und achten Sie besonders darauf, wie die ›5‹ und die Regex sich gegenseitig beeinflussen.
Retrospektiv betrachtet, ist das Problem recht einfach. Wir steigen an der Stelle ein, wo ˹(\.\d\d[1-9]?)\d+˼ den String 27.625 erkannt hat, und wir sehen, dass das ˹\d+˼ nicht passt. Das ist kein Problem für den Automaten, denn der Treffer von ˹[1-9]˼ auf ›5‹ war optional, und dazu gibt es einen gespeicherten Zustand. Mit diesem Weg passt ˹[1-9]?˼ auf gar nichts, und die 5 wird vom geforderten »mindestens einmal« des ˹\d+˼ geschluckt. So erhalten wir einen Treffer für den ganzen Ausdruck, aber den falschen: .625 wird durch .62 ersetzt, und der Wert in $kurs wird unrichtig.
Und wenn wir die nicht-gierige Version von ˹[1-9]?˼ genommen hätten? Wir hätten den gleichen Treffer bekommen, aber ohne dass zwischendrin die 5 erkannt und zurückgegeben worden wäre, weil ja das ˹[1-9]??˼ zuerst versucht, gar nicht zu passen. Nicht-gierige Quantoren sind hier also keine Lösung.
<< zurück | vor >> |
Tipp der data2type-Redaktion: Zum Thema Reguläre Ausdrücke bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an: |
Copyright der deutschen Ausgabe © 2008 by O’Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "Reguläre Ausdrücke" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.
O’Reilly Verlag GmbH & Co. KG, Balthasarstr. 81, 50670 Köln