Jeste jsem si s tim nejakou dobu hral a zkousel ...
Priklad od Ghosta funguje perfektne. Trochu jsem ho upravil na zaklade navrhu Logika, ale bud jsem to neudelal dobre nebo je chyba jinde (je rozhodne pomalejsi).
Mozna nakonec to, ze Ghost "$_string" ukusuje, je pro vykon lepsi nez prochazeni celeho textu pomoci indexu a offsetu.
Sazeni vysledku do pole a nasledny implode (namisto rozsirovani stavajiciho stringu) nemelo temer zadny vliv na pamet i vykon (nebo opravdu velmi zanedbatelny).
Nakonec jsem otestoval celkem 4 reseni na textu dlouhem 1.5MB (1.564.135 slov, 172.109 slov), testovaci podminky byly shodne a pred kazdym testem jsem restartoval apache.
Vysledky jsou nasledujici:
# Ghostovo originalni reseni
highlight MEM: 1707,292 kB, Time: 13,8758 s
# Uprava Ghostova reseni
highlight2 MEM: 1707,360 kB, Time: 17,7329 s
function highlight2($search, $string) {
$_search = strtolower(iconv("UTF-8","ASCII//TRANSLIT", $search));
$_string = strtolower(iconv("UTF-8","ASCII//TRANSLIT", $string));
$result = "";
$len=strlen($_search);
// Vychozi offset
$offset=0;
// Hledame pozici prvniho vyskytu hledaneho; bereme v potaz offset
while(($lastIndex = strpos($_string, $_search, $offset)) !== false) {
// zacatek vyrazu (zaciname na offsetu)
$start = mb_substr($string, $offset, ($lastIndex-$offset), "UTF-8");
// hledany vyraz
$middle = "<b>".mb_substr($string, $lastIndex, $len, "UTF-8")."</b>";
// pripojime do vysledku
$result .= $start.$middle;
// Nastavime novy offset
$offset=($lastIndex+$len);
}
// Pripojime konec textu (bereme v potaz offset)
$result.=mb_substr($string,$offset,mb_strlen($string,"UTF-8"),"UTF-8");
return mb_strlen($result, "UTF-8") ? $result : $string;
}
# Index pozic pomoci preg_match_all()
highlight3 MEM: 1794,860 kB, Time: 15,4054 s
function highlight3($needle,$haystack,$type="need") {
// Transliterace
$ASCII_haystack=strtolower(iconv("UTF-8","ASCII//TRANSLIT",$haystack));
$ASCII_needle=strtolower(iconv("UTF-8","ASCII//TRANSLIT",$needle));
// Delka hledaneho
$len=strlen($ASCII_needle);
// preg_match_all nam naplni pole pozicemi hledaneho vyrazu
preg_match_all("/$ASCII_needle/",$ASCII_haystack,$m,PREG_OFFSET_CAPTURE);
// Vychozi offset
$offset=0;
// Prochazeni pole s pozicemi kazdeho vyskytu
foreach($m[0] as $p) {
// Pozice vyskytu
$pos=$p[1];
// Zacatek vyrazu
$start=mb_substr($haystack,$offset,($pos-$offset),"UTF-8");
// Zvyrazneni
$word="<strong>".mb_substr($haystack,$pos,$len,"UTF-8")."</strong>";
// Pripojeni do vysledku
$out.=$start.$word;
// Novy offset
$offset=($pos+$len);
}
// Konec vyrazu do vysledku
$out.=mb_substr($haystack,$offset,mb_strlen($haystack,"UTF-8"),"UTF-8");
return $out;
}
# Diakritika / alternativy pomoci preg_replace()
Nejvice naroku na pamet i cas. Zase na druhou stranu to je jednoduche a diky regexpum se to da velice dobre rozsirovat.
highlight4 MEM: 3261,516 kB, Time: 17,8068 s
function highlight4($needle,$haystack,$type="need") {
// Priprava na slozeni regexpu (obsazeni temer vsech moznych akcentu)
$map1[]="/[aãǎâăåąàȧáä]/iu";
$map1[]="/[bḃ]/iu";
$map1[]="/[cčĉċćç]/iu";
$map1[]="/[dďḋḑ]/iu";
$map1[]="/[eěêĕęèéëȩ]/iu";
$map1[]="/[fḟ]/iu";
$map1[]="/[gǧĝġǵģ]/iu";
$map1[]="/[hȟĥḣḧḩ]/iu";
$map1[]="/[iĩǐîĭįìıíï]/iu";
$map1[]="/[jǰĵ]/iu";
$map1[]="/[kǩḱķ]/iu";
$map1[]="/[lľĺļ]/iu";
$map1[]="/[mṁḿ]/iu";
$map1[]="/[nñňǹṅńņ]/iu";
$map1[]="/[oõǒôŏǫòȯóőö]/iu";
$map1[]="/[pṗṕþ]/iu";
$map1[]="/[rřṙŕŗ]/iu";
$map1[]="/[sšŝṡśş]/iu";
$map1[]="/[tťṫẗţ]/iu";
$map1[]="/[uũǔûŭůųùúűü]/iu";
$map1[]="/[vṽ]/iu";
$map1[]="/[wŵẘẁẇẃẅ]/iu";
$map1[]="/[xẋ]/iu";
$map1[]="/[yỹŷẙỳẏýÿ]/iu";
$map1[]="/[zžẑżź]/iu";
// Slozeni regexpu
$map2[]="[aãǎâăåąàȧáä]";
$map2[]="[bḃ]";
$map2[]="[cčĉċćç]";
$map2[]="[dďḋḑ]";
$map2[]="[eěêĕęèéëȩ]";
$map2[]="[fḟ]";
$map2[]="[gǧĝġǵģ]";
$map2[]="[hȟĥḣḧḩ]";
$map2[]="[iĩǐîĭįìıíï]";
$map2[]="[jǰĵ]";
$map2[]="[kǩḱķ]";
$map2[]="[lľĺļ]";
$map2[]="[mṁḿ]";
$map2[]="[nñňǹṅńņ]";
$map2[]="[oõǒôŏǫòȯóőö]";
$map2[]="[pṗṕþ]";
$map2[]="[rřṙŕŗ]";
$map2[]="[sšŝṡśş]";
$map2[]="[tťṫẗţ]";
$map2[]="[uũǔûŭůųùúűü]";
$map2[]="[vṽ]";
$map2[]="[wŵẘẁẇẃẅ]";
$map2[]="[xẋ]";
$map2[]="[yỹŷẙỳẏýÿ]";
$map2[]="[zžẑżź]";
// Nahrazeni hledaneho vyrazu regexpem
// "pocitac" se bude hledat jako: [pṗṕþ][oõǒôŏǫòȯóőö][cčĉċćç][iĩǐîĭįìıíï][tťṫẗţ][aãǎâăåąàȧáä][cčĉċćç]
$needle=preg_replace($map1,$map2,$needle);
// Finalni nahrazeni hledaneho vyrazu v textu
$haystack=preg_replace("/[^\s]*${needle}[^\s\.]*/iu","<strong>\$0</strong>",$haystack);
return $haystack;
}