Warum RegEx statt String Funktionen in PHP

Reguläre Ausdrücke haben eine ganze Menge Vorteile

Warum RegEx statt String Funktionen in PHP

In meiner Programmierpraxis erlebe ich immer häufiger das ich statt der PHP eigenen Stringfunktionen immer öfter einfach reguläre Ausdrücke benutze.  Warum ist das eigentlich so? 

Bei naherer Überlegung gibt es da schon so einige Gründe:

  • Portierbarkeit 
  • Unicode kompatibel
  • Einheitliche Syntax
  • Es gibt einfach zu viele String Funktionen
  • Kaum langsamer, teilweise sogar schneller.
  • Wesentlich mächtiger. 

Wenn man das alles zusammen nimmt ist es nicht wirklich verwunderlich das man sobald man sich mit regulären Ausdrücken auskennt, einfach dazu tendiert Vieles auch damit zu machen. Aber schauen wir uns die Gründe mal im einzelnen an:

Portierbarkeit

Regulare Ausdrücke gibt es in beinahe jeder Programmiersprache das macht die Portierung natürlich einfach. Geringfügige Unterschiede gibt es zwar, aber meistens sind da keine wirklichen Unterschiede sondern eher das einige besondere Features nicht implementiert wurden. Die Ähnlichkeit ist in jedem Fall groß genug das Jeder, der sich einmal ausführlich mit RegEx auseinandergesetzt hat, in der Lage ist eine solchen Ausdruck zu Lesen und zu verstehen. Ganz im Gegensatz zu den Stringfunktionen die fast immer einen Blick ins Handbuch erfordern.

Unicode Kompatibel

Was habe ich mich in PHP schon geärgert wenn mal wieder eine Stringfunktion nicht Unicode bzw Multibyte kompatibel  war. Das Programm produziert seltsame Ergebnisse und ich durfte schon wieder mal raten welche Funktion sich so funktioniert wie ich das gerne hätte. Also PHP Manual öffen und suchen bis man dann feststellt das eine bestimmte Funktion gar keine Option für Unicode hat oder nur unter bestimmten Bedingungen funktioniert. 

Einheitliche Syntax

Oft habe ich das Gefühl, das bei der Erstellung der PHP Stringfunktionen jemand einen Würfel genommen hat und die Reihenfolge der Parameter einfach ausgewürfelt hat. Alles ist irgendwie inkonsistent. (Wer es nicht glaubt, schaue einfach mal hier: PHP: a fractal of bad design )  Da stechen die Preg Funktionen noch als zuverlässiges Beispiel hervor. Die Parameter sind in logischer Reihenvolge, immer gleich wenn es sinnvoll ist und es sind grade mal 7 Funktionen mit halbwegs sinnvollen Unterschieden. Wobei auch hier PHP alles aufbläht, denn bei PERL zum Beispiel sind diese Sachen einfach in die Sprache integriert.

Suchen und Ersetzen mir regulärem Ausdruck in PHP und PERL: 

$regtest =~ s/e/-e-/;                                    //PERL
$regtest = preg_replace ("/e/", "-e-", $regtest) ;       //PHP

Noch ein paar Inkonsistenzen gefällig:

  • Unterstrich oder doch nicht:  strpos / str_rot13
  • “to” oder  2: bin2hex, deg2rad, strtolower, strtotime
  • Objekt+Verb oder Verb+Objekt: base64_decode, str_shuffle, var_dump , recode_string
  • "str" oder doch "string": is_string, recode_string, strpos, str_shuffle
  • Reihenfolge der Argumente: strpos($haystack, $needle) versus array_search($needle, $haystack)
  • Warum zur Hölle braucht man für Groß und Kleinschreibung extra Funktionen?
  • htmlentities und html_entity_decode zum Beispiel, sie gehören  Beide zusammen aber haben völlig unterschiedliche Namenskonventionen.

Da bin ich einfach froh wenn ich 90%-95% aller Probleme mit preg_match, preg_split und preg_replace lösen kann.

Zu viele Stringfunktionen

PERL kommt mit 7 Funktionen aus, 8 wen man eval() dazuzählt: Perl Stringfunktionen.

PHP beglückt uns mit etwa 97 die teilweise nur den Unterschied haben das sie Groß- und Kleinschreibung beherrschen. PHP Stringfunktionen. 

Warum soll ich mir das alles merken, wenns viel einfacher geht.

Kaum langsamer, teilweise sogar schneller.

Thiemo Mättig hat zu dem Thema ein tolles Benchmark gebastelt: http://maettig.com/code/php/php-performance-benchmarks.php

Allerding sehe ich die Ergebnisse doch ein klein wenig anders. Die Art wie die Ergebnisse auf addiert wurden und daraus ein Index errechnet wurde ist. Naja, es hat halt einen gewissen Katapulteffekt und stellt die Unterschiede deutlich größer dar als sie eigentlich sind. 

Aber egal werfen wir mal einen Blick auf die Resultate:

Check if a String contains another String

"strstr"  braucht im Duchschnitt 1 ms 
"stristr" braucht schon 2ms 
"preg_match" braucht auch 2ms 

Warum also nicht gleich preg_match, zumal das auch UTF8 kann und mit Zeilenumbrüchen umgehen kann.

 

Check if a String ends with another String

"substr" braucht im Durchschnitt 2ms
"preg_match" braucht 4ms 

Das ist etwa doppelt so lange, allerdings immer noch sehr schnell und in vielen Fällen könnte man das preg_quote weglassen. 

 

Replace a String inside another String

"str_replace" ist flott mit 2 ms Durchschnitt
"preg_replace" auch mit 4ms 
"strstr" ganz übel mit 13ms

Bei preg_replace kann ich mich drauf verlassen das es immer recht zügig funktioniert, bei den String Funktionen erlebt man immer wieder Überraschungen.

 

Trim Characters from the Beginning and End of a String

"trim"  weniger als 1ms
"preg_replace"  weniger als 1ms

Von der Zeit her vernachlässigbar, allerdings nutze ich auch oft trim() weils einfach einfacher ist. 

 

Split a String into an Array

"explode" braucht im Schnitt 3 ms
"preg_split" braucht im Schnitt  5,3 ms

Ja, auch wieder etwas langsamer, allerdings wenn es darum geht komplexe Trennstellen zu finden geht explode unter. 

 

Fazit

Reguläre Ausdrücke sind ein wenig langsamer als die jeweils schnellste PHP Funktion, allerdings muss man auch erst einmal wissen welche in dem speziellen Fall die Schnellste ist. Wer geht schon vorher hin und fängt an für jeden Spezialfall alle Funktionen zu Benchmarken? Wenn es dann noch um Texte in heute durchaus häufig vorkommenden UTF8 geht dann gehen die PHP Funktionen gnadenlos unter. Obendrein muß man sich nicht mit ständig ändernden Parameterreihenfolgen rumschlagen, hier z.B. :

trim($string, ",")    //erst String dann das Zeichen
explode(",", $string) // erst das Zeichen, dan der String

Wer weiss das schon immer auswendig?

Wesentlich Mächtiger

Alleine schon der Versuch eine Email Validierung wie diese:

/^((([!#$%&'*+\\-\/\=?^_`{|}~\w])|([!#$%&'*+\\-\/\=?^_`{|}~\w][!#$%&'*+\\-\/\=?^_`{|}~\.\w]{0,}[!#$%&'*+\\-\/\=?^_`{|}~\w]))[@]\w+(([-.]|\-\-)\w+)*\.\w+(([-.]|\-\-)\w+)*)$/

Mit PHP Stringfunktionen zu realisieren, dürfte mehr als abenteuerlich werden. Wenn das jetzt noch verschiedene Zeichenkodierungen mitspielen würden.... Unmöglich. Aber auch schon wenn man einfach nur ein wenig Mehr benötig stoßen PHP Stringfunktionen schon schnell an ihre Grenze. Angenommen wir haben einen Text und wir möchten einfach nur doppelte Leerzeichen entfernen.

$text="hello     what\t\tis  my\r\n    name";

Mit RegEx:

$text = preg_replace('/\ +/', ' ', $text]);

Mit str_replace():

$count = 1;
while($count){
    $text = str_replace('  ', ' ', $text, $count);
​}

Das geht noch, wird aber schon, naja unpraktisch. aber jetzt wollen wir noch Tabulatoren entfernen und auch die Zeilenumbrüche. Bei dem Regulären Ausdruck ändert sich fast nichts.

$text = preg_replace('/\s+/', ' ', $text]);

Aber mit str_replace wirds schon interessant.

$count = 1;
while($count){
    $text = str_replace('  ', ' ', $text, $count);
​}
$text = str_replace("\t", '', $text, $count);
​$text = str_replace("\r", '', $text, $count);
$text = str_replace("\n", '', $text, $count);
​

Wenn jetzt aber im Text der Tabulator anstelle eines Leerzeichens genommen wurde dan kleben jetzt 2 Worte hintereinander , ersetzen wir den Tabulator statt dessen mit einem Leerzeichen , dann haben wir wieder 2 Leerzeichen..... Es wird halt einfach unpraktisch und kompliziert.

 

Das könnte Sie auch interessieren

Die ersten 100 Zeichen eines Textes
oder vielleicht auch die letzten ?
Diese Seite ist ein Experiment in Dom Templating Diese Seite
Willkommen auf meiner Homepage!
PHP und CSRF, Schutz vor Angriffen CSRF, Schutz vor Angriffen
Immer noch in den Top Ten der beliebtesten Angriffe. Die CRSF Attacke.

Kommentar schreiben

In der Ehe besonders - aber eigentlich überall - ist der große Irrtum,
daß man glaubt, sobald man seinen Wert, sei es schreibend oder
handelnd, dem andern feurig gezeigt und eingeprägt, man habe in den
matten Tagen des Lebens dieselbe feurige Darstellung des Innern nicht
zu wiederholen, sondern auf die erste zu bauen. Das Wiederkommen der
Zeit fodert Erneuerung des ersten Eindrucks und um so mehr, je größer
er war.
-- Jean Paul