Thread backreferences und '\n' (14 answers)
Opened by snarf at 2006-03-29 15:15

sid burn
 2006-03-30 19:50
#64177 #64177
User since
2006-03-29
1520 Artikel
BenutzerIn

user image
[quote=snarf,30.Mar..2006, 09:43]
Quote
Die bedeutung Single/Multi line ist auch nicht wirklich passend.


Darf ich dann fragen, was Du hier für passender hälst???

Gruß
Dirk[/quote]
Eine kurze passendere Beschreibung wüste ich auf anhieb auch nicht. Allerdings suggeriert single/multi line Modus doch, dass die Variable auf der wir die regex anwenden anders behandelt wird. Dies ist aber nicht der Fall. Genauso kann man denken das eine gleichzeitige Verwendung von single/multi line Modus nicht Funktioniert, oder es keinen Sinn ergibt. Aber man kann schon beide Optionen zusammen verwenden.

Das kann man in "perldoc perlre" nachschlagen.

Ich würde die Optionen jedenfalls so umbennen, auf das was sie wirklich machen. Also für /s "Verändert die Bedeutung des Punktes" und für /m "Verändert die Bedeutung von Zirkumflex und Dollarzeichen.

Die Sache ist halt nur die, dass diese Veränderung letztendlich schon dazu führen das eine Veriable als Single Line oder Multi Line anerkannt wird. Allerdings nur, wenn man halt diese Zeichen benutzt.

Auch denken viele das wenn sie eine Variable benutzen die mehrere Zeilen enthält, dass Sie automatisch /m oder /s benutzen müssen. Halt wegem dem Multi Line Modus. Wenn Sie aber "^" , "$" oder "." nicht in ihrer Regex verwenden braucht man diese Option nicht. Die Option bewirkt letztendlich nichts.


Zum anderen liest man in vielen Einführungen von Regulären Ausdrücken immer eine Falsche Bedeutung des Punktes. Meistens liest man das der Punkt auf jedes Zeichen passt. Was aber falsch ist. Der Punkt passt auf jedes Zeichen das nicht ein Newline Zeichen ist. Es ist also Vergleichbar mit [^\n].

Wenn man diese Tatsache weiß, dann ist es letztendlich auch nicht verwunderlich warum deine erste Regex nicht funktionierte. Den das ".+" frisst erst alle Zeichen bis zum Newline Zeichen auf, und wird dann mittels Backtracking gezwungen auf das "}" zu matchen. Wenn aber halt auf der selben Zeile kein "}" vorkommt, dann passt deine Regex nicht, und macht letztendlich mit dem nächsten "{" Zeichen weiter. Da du aber mit dem Punkt nie über eine Zeile hinweg kommst, machst du deine Suche nicht über mehrere logische Zeilen.

Du hast entweder die wahl die Bedeutung des Punktes zu verändert, oder eben einen Ausdruck zu benutzen der auch auf "\n" passt, aber eben nicht auf das Zeichen, was du als nächstes benötigst. Das wäre wie Taulmarill schrieb am besten " [^}] " was auf jedes Zeichen passt auser dem "}". Es passt also letztendlich auch auf das Newline Zeichen.

Die Option /s oder /m benötigen wir nicht. Da wir nirgendswo ein Punkt, Zirkumflex oder ein Dollar Zeichen benutzen, obwohl unsere variable aus mehreren Zeilen besteht.

Von daher würde ich schon sagen das /s oder /m auf den ersten Blick, oder für jemanden der sich nicht so viel mit Regulären Ausdrücken beschäftigt keine richtige und eindeutige Bezeichnung ist.

Ich hoffe meine Erklärung ist nachzuvollziehen.

---------

Zum anderen würde ich dir auch raten lieber Taulmarills Lösung zu benutzen. Dein Fehler in der Regex ist folgender das erst nach einem "{" gesucht wird. Danach wird mit ".+" die komplette restliche Datei eingelesen, bis zum EOF. Danach wird mittels BackTracking solange zurück gegangen wie ein "}" gefunden wird.

Wenn du das auf eine 100MB Datei anwendest, und am anfang und am ende jeweils ein "{" oder "}" steht, dann müsste letztendlich die komplette 100MB nochmal zusätzlich in $1 gespeichert werden. Und dann findet erst eine ersetzung statt. Existiert keine richtige Anzahl von öffnenden und schließenden Klammern in deiner Datei, Funktioniert deine Regex auch nicht richtig, so wie meine Lösung.

Es kommt dann bei solch einem String.
"print { "hallo, welt" } print; }"
folgendes bei deiner Regex heraus.
"print {{ "hallo, welt" } print; }}"

Besser wäre es wenn du zumindest einen nicht gierigen Operator, also ".+?" benutzt. Dann würde das gleiche Ergebnis heraus kommen wie Taulmarills Lösung. Er würde auch nicht sofort alles bis zum EOF einlesen, wäre also Speicherschonender und schneller.

Allerdings ist Taulmarills Lösung trotzdem noch effizenter, da durch einen nicht gierigen Operator eine Menge Backtracking Operationen ausgeführt werden.

Wenn ich aber jetzt schon über effizenz rede, dann könnte man Taulmarills Lösung noch effizenter machen, wenn man Atomare Klammern hinzufügen würde.

Code: (dl )
1
2
3
4
5
6
7
8
s/(
{
(?>
[^}]+
)
}
)
/{$1}/gx;

Dadurch wird ein Ergebnis im Fehlerfall (keine schließende Klammer) schneller gefunden.

Ich schreibe schon wieder zu viel...\n\n

<!--EDIT|sid burn|1143736266-->
Nicht mehr aktiv. Bei Kontakt: ICQ: 404181669 E-Mail: perl@david-raab.de

View full thread backreferences und '\n'