Ich suche in einem String nach Teilstrings, die ich in einem Array habe. Die Funktion array_search macht leider genau das Gegenteil, deshalb brauche ich an dieser Stelle eine eigene Funktion.
Doch welche String-Suchfunktion verwende ich?
Zur Auswahl stehen folgende Funktionen, sollte ich was vergessen haben bitte ich um kurze Meldung:
Hier mal der Versuch einer Messung, wie schnell die Funktionen ihre Arbeit erledigen. Dazu lasse ich alle Funktionen nacheinander den String durchsuchen, das ganze mache ich je Funktion 9999 mal, um eine Tendenz sichtbar zu machen. Und ja: Quick and Dirty Code, ich bin mir dessen bewusst.
$arrHaystack = array( 'hallo',
'welt',
'foobar',
'php5',
'suchfunktion',
'bob',
'und',
'alice',
'suchen',
'strings',
'in',
'arrays',
'Lorem','ipsum','dolor','sit','amet','consetetur','sadipscing','elitr','sed','diam','nonumy','eirmod','tempor','invidunt','ut','labore','et','dolore','magna','aliquyam','erat','sed','diam','voluptua','At','vero','eos','et','accusam','et','justo','duo','dolores','et','ea','rebum','Stet','clita','kasd','gubergren','no','sea','takimata','sanctus','est','Lorem','ipsum','dolor','sit','amet','Lorem','ipsum','dolor','sit','amet','consetetur','sadipscing','elitr','sed','diam','nonumy','eirmod','tempor','invidunt','ut','labore','et','dolore','magna','aliquyam','erat','sed','diam','voluptua','At','vero','eos','et','accusam','et','justo','duo','dolores','et','ea','rebum','Stet','clita','kasd','gubergren','no','sea','takimata','sanctus','est','Lorem','ipsum','dolor','sit','amet','Lorem','ipsum','dolor','sit','amet','consetetur','sadipscing','elitr','sed','diam','nonumy','eirmod','tempor','invidunt','ut','labore','et','dolore','magna','aliquyam','erat','sed','diam','voluptua','At','vero','eos','et','accusam','et','justo','duo','dolores','et','ea','rebum','Stet','clita','kasd','gubergren','no','sea','takimata','sanctus','est','Lorem','ipsum','dolor','sit','amet','Duis','autem','vel','eum','iriure','dolor','in','hendrerit','in','vulputate','velit','esse','molestie','consequat','vel','illum','dolore','eu','feugiat','nulla','facilisis','at','vero','eros','et','accumsan','et','iusto','odio','dignissim','qui','blandit','praesent','luptatum','zzril','delenit','augue','duis','dolore','te','feugait','nulla','facilisi','Lorem','ipsum','dolor','sit','amet','consectetuer','adipiscing','elit','sed','diam','nonummy','nibh','euismod','tincidunt','ut','laoreet','dolore','magna','aliquam','erat','volutpat');
$iIterations = 100;
$suchsatz = array('meas magna','mia diam','im garten sind bob und alice','elixier des nichts');
$iMax = count($suchsatz);
$iStart = microtime(1);
for ($i=0;$i<$iIterations;$i++)
{
$iTake = mt_rand(0, $iMax);
foreach ($arrHaystack AS $key => $value)
{
if (mb_substr_count($suchsatz[$iTake], $value)>0)
{
break;
}
}
shuffle($arrHaystack);
}
$iEnd1 = microtime(1);
for ($i=0;$i<$iIterations;$i++)
{
$iTake = mt_rand(0, $iMax);
foreach ($arrHaystack AS $key => $value)
{
if (mb_stripos($suchsatz[$iTake], $value)!==FALSE)
{
break;
}
}
shuffle($arrHaystack);
}
$iEnd2 = microtime(1);
for ($i=0;$i<$iIterations;$i++)
{
$iTake = mt_rand(0, $iMax);
foreach ($arrHaystack AS $key => $value)
{
if (mb_stristr($suchsatz[$iTake], $value)!==FALSE)
{
break;
}
}
shuffle($arrHaystack);
}
$iEnd3 = microtime(1);
for ($i=0;$i<$iIterations;$i++)
{
$iTake = mt_rand(0, $iMax);
foreach ($arrHaystack AS $key => $value)
{
if (preg_match('/'.$value.'/i', $suchsatz[$iTake])>0)
{
break;
}
}
shuffle($arrHaystack);
}
$iEnd4 = microtime(1);
printf('--------------------------'."\n");
printf('mb_substr_count() -> %f'."\n",$iEnd1-$iStart);
printf('mb_stripos() -> %f'."\n",$iEnd2-$iEnd1);
printf('mb_stristr() -> %f'."\n",$iEnd3-$iEnd2);
printf('preg_match() -> %f'."\n",$iEnd4-$iEnd3);
printf('--------------------------'."\n");
Hier die Ergebnisse:
————————–
mb_substr_count() -> 15.756097
mb_stripos -> 16.490042
mb_stristr -> 16.938911
preg_match -> 14.681287
————————–
Schön zu sehen, dass meine intuitiv gewählte Funktion mb_substr_count() die Arbeit anscheinend am schnellsten erledigt. Überraschend für mich, dass der regex Platz 2 belegt und dass die anderen Funktionen einen so großen Abstand zu den beiden ersten Plätzen aufweisen.
Update 08.01.2011:
Habe den Code mal den Kommentaren angepasst. Das Array der Wörter ist nun 240 Felder groß, es wird nun auch zufällig einer von 4 Sätzen durchsucht. Nach jedem Treffer wird das Wort-Array zufällig neu ‚geschüttelt‘. Das sollte alle Caching-Sachen ausschalten.
Dabei bildet sich wirklich ein neues Bild (bei 100 durchläufen). Platz 1 geht nun an den regex, Platz 2 an substr_count, dicht gefolgt von den beiden stri-Funktionen. Insgesamt ist aber kein nennenswerter Abstand mehr vorhanden (im Gegensatz zum ersten Test), weshalb ich sagen kann: Nehmt, womit ihr am besten klarkommt. In High-Performance Umgebungen folgt dem Testergebnis.