Thread Viele RegExp Checks auf viele Dateien (17 answers)
Opened by Tr0Nix at 2007-12-21 10:51

sid burn
 2008-01-06 16:18
#104444 #104444
User since
2006-03-29
1520 Artikel
BenutzerIn

user image
1) Das wichtigste bei Regexen ist das sie bei einem nicht matchen sich möglichst schnell beenden. Dafür musst du Wissen wie eine Regex Engine einen Treffer findet (also Backtracking muss dir ein Begriff sein). In vielen fällen kannst du dann Backtracking Informationen mit (?>) löschen lassen. Allerdiengs musst du selber Wissen was du da tust. Die falsche verwendung kann dazu führen das deine Regexe nicht mehr das Matchen was du eigentlich wolltest.

2) Weiterhin sollte man den "|" Operator vermeiden wenn es geht. Dieser ist nicht gerade der schnellste. Anstatt 100 Werte mit einem "|" zusammenzufügen ist es schneller die 100 Werte einzelnt auf einen String zu prüfen.

3) Anstatt vieles in einer Regex zu machen sollte man wenn es geht alles auf mehrere Regexe aufsplitten. Wenn man z.B. Whitespace zeichen am Anfang und Ende einer Zeile entfernen möchte kann man das in einem Ausdruck machen oder in zwei aufteilen.

Code: (dl )
1
2
3
4
$string =~ s/^\s*(.*?)\s*$//;

$string =~ s/^\s+//;
$string =~ s/\s+$//;


Die unteren beiden sind viel schneller, auch weil sie eine abbruch bedienung haben. Wenn kein Whitespace Zeichen vorkommt findet keine Substitution statt, oben findet sie immer statt. Und zwei einfache Regexe sind schneller als eine Komplizierte.

3) Wichtig ist es du nutzt Anker. Wenn also etwas nur am Anfang/Ende oder nach etwas stehen darf, dann solltest du diese Sachen hinzufügen. Teilweise musst du es natürlich auch damit deine Regex überhaupt Korrekt arbeitet. Ein Beispiel:

Code: (dl )
1
2
3
4
my $string = "Programm Version 1.2.3 next relase foo bar"

if ( $string =~ m/ ( [\d.]+ ) /x ) { ... }
if ( $string =~ m/ Version ( [\d.]+ ) /x { ... }

Die zweite Regex ist schneller. Bei der ersten regex wird letztendlich jede Position des String auf einer Zahl oder Punkt untersucht und das erste finden wird dann in $1 gespeichert.

Bei der zweiten Regex dient "Version" als Anker. Die Regex Engine ist verdammt Schnell fertige Texte zu Finden, und kann Praktisch direkt nach "Version" anfangen zu Prüfen, ohne die ZEichen davor zu testen. Auch bei einem Fehler nach Version würde es nicht jede Position weiter Testen, da nirgendswo "Version" vorkommt und die Regex im Fehlerfall schneller beendet ist.

Anker können Text ausschnitte sein oder z.B: ^ $ \b


4) Du solltest die Variablen $' $& $`vermeiden.

5) Wenn du die Regexe immer wieder nutzt dann ist gut die Regexe vorzukompilieren und in einem qr// abzulegen. Wenn du nur ein Match machst dann solltest du auch folgende Schreibweise nutzen.

Code: (dl )
$string =~ $vorkompillierte_regexe_mit_qr

anstatt
Code: (dl )
$string =~ m/$vorkompillierte_regexe_mit_qr/


Das erste ist nochmal schneller.

6) Die Option /o:
Diese Option kann deine Performance verbessern wenn Variablen in deiner Regexe auftauchen die Interpoliert werden. Aber auch nur dann. Weiterhin muss die Bedienung erfüllt sein dass diese Variable sich nie mehr ändern soll. Wenn du /o an deiner Regex anhängst dann wird die Regex einmal Kompiliert und für immer so genutzt wie sie beim Kompilieren war. Selbst wenn sich die interpolierten Variablen ändern sollten bleibt die Regex wie beim ersten Kompilieren.

Wenn du also Variablen in einer Regex nutzt die sich definitiv nicht mehr ändern, dann kannst du /o nehmen. Damit muss Perl nicht ständig checken ob sich die Variable verändert hat.

7) Die Funktion study:
Bei bestimmten Anforderungen kannst du auf einen String die Funktion "study" anwenden. Diese Funktion cached bestimmte Teile des Strings und macht das ausführen der Regexe schneller. Allerdiengs gibt es etliche Bedienungen die erfüllt sein müssen damit stidy auch einen Performance schub bringt, anstatt es dein Programm langsamer macht.

Generell funktioniert es so das es Teile deines String abspeichert und Optimierungen abspeichert. Das kostet dich Speichern (kann bis zu viemal so groß sein wie der String selber) und natürlich auch etliches an Rechenkaft die erstmal generiert werden muss. Wenn du study() einfach so auf jeden String anwendest kann es auch dein Programm verlangsamen da der Overhead zur erstellung der Optimierung länger dauert als das reine matchen. Du musst also sicherstellen das du mehr matchest machst als die erzeugung des Overheads.

Weiterhin bringt die Optimierung nur dann etwas wenn sich der zu durchsuchende String nicht mehr verändert. Sollte sich der String verändern. z.B. weil du eine Substitution machst, dann ist die ganze Optimierung zu nichte. Du darfst also nur matchen nicht Substituieren.

Weitere bedienungen die erfüllt sein müssen:
- Die Regexe dürfen die Option /i oder (?i:) darf in den Regexen nicht vorkommen. Diese machen die Optimierung von study kaputt: Du musst also ein "test" so umschreiben: [Tt][Ee][Ss][Tt]
- Man sollte es nicht bei kurzen Suchstrings nutzen. Was genau "kurz" ist hängt sehr von deinen Daten und Regexen ab die du verwendest. Als grobe Faustregel sollte ein String mehrere Killobyte groß sein bis sich eine verwendung lohnt.
- Und nochmal erwähnt: Du musst viele Matchings machen, sonst lohnt sich der Overhead durch Sudy nicht.
- Der zu durchsuchende String darf sich nicht ändern.
- Du solltest study nur dann nutzen wenn in deinen Regexen feste Textteile enthalten sind (also zeichen die definitiv in der Regex vorkommen müssen). Siehe Punkt 3) Anker den genau das ist das was study cached.

Aus deiner Beschreibung heraus kann study() dir wahrscheinlich helfen. Du solltest dann die Dateien komplett im Speicher in einem String einlesen, und study dann auf diesen String anwenden.

8) Nicht wirklich ein Tipp. Aber das bereits genannte Buch Reguläre Ausdrücke kann ich dir nur wärmsten ans Herz legen. Auch wenn es sicherlich untergegangen ist, aber der Punkt 1) ist der allerwichtigste von allen. Du musst deine Regex so schreiben das sie frühstmöglichst erkennen wenn sie auf einen String nicht matchen und sich dann auch sofort beenden, anstatt noch jede Möglich Kombination weiter auszuprobieren. Aber gerade der Punkt ist am schwierigsten zu Erklären. Aber dafür ist das Buch zuständig. Dies erklärt dir das ausführlich.
Nicht mehr aktiv. Bei Kontakt: ICQ: 404181669 E-Mail: perl@david-raab.de

View full thread Viele RegExp Checks auf viele Dateien