Zvýraznění výsledků vyhledávání
Když už si na stránkách dáme práci s implementací vyhledávání, je užitečné nalezená slova vhodně zvýraznit. Kdokoliv k tomu sice může použít vyhledávání dostupné přímo v prohlížeči, ale trocha pohodlí návštěvníky jistě potěší. Zvýrazňování se dá zajistit buď u každého vypisovaného textu zvlášť (na což je ale jednoduché zapomenout, znepřehledňuje to kód a nedá se to použít u statických textů vypisovaných mimo PHP) nebo společně pro celou stránku s využitím funkce ob_start.
<?php function odzvyraznit($matches) { return preg_replace('~<span class="search-result">([^<]*)</span>~i', '\\1', $matches[0]); } function zvyraznit($text) { $search = preg_quote(htmlspecialchars($_GET["search"]), '~'); if ($search) { $text = preg_replace("~$search~i", '<span class="search-result">\\0</span>', $text); // odstranění zvýrazňování z obsahu <option> a <textarea> a zevnitř značek a entit $span = '<span class="search-result">[^<]*</span>'; $pattern = "~<(option|textarea)[\\s>]([^<]*$span)+|<([^>]*$span)+|&([^;]*$span)+~i"; $text = preg_replace_callback($pattern, 'odzvyraznit', $text); } return $text; } // zvýrazňování pro každý vypisovaný text zvlášť echo "<h1>" . zvyraznit($row["nadpis"]) . "</h1>\n"; echo zvyraznit($row["clanek"]); // obdobně diskuse a spol., statické texty je nutné převést do PHP // zvýrazňování pro celou stránku ob_start('zvyraznit'); // umístit před začátek zvýrazňovaného textu echo "<h1>$row[nadpis]</h1>\n"; echo $row["clanek"]; // diskuse, statické texty, ... ob_end_flush(); // umístit za konec zvýrazňovaného textu - pokud odpovídá konci dokumentu, lze vynechat ?>
Pokud nepoužíváte zalomení konce řádků uvnitř značek (tedy např. <a\nhref="">
), dá se funkci ob_start předat druhý parametr, který zajistí plynulé vypisování výstupu na straně serveru. Zvýrazňování si nerozumí s kódem uvnitř značky <script>
. Ale vzhledem k tomu, že při tomto použití značky nejde HTML kód napsat zároveň zpětně a dopředně kompatibilní, je stejně lepší se mu vyhnout v jakémkoliv dokumentu a skripty vkládat vždy externě (důvod je ten, že HTML doporučuje kód uzavírat do HTML komentářů, ale XML parser používaný v XHTML může text uvnitř těchto komentářů bez varování odstranit).
Nejlepší na tom všem je, že tento způsob se dá použít nejen pro zvýraznění výsledků interního vyhledávání, ale dá se použít i pro zvýraznění hledání externím vyhledávačem (např. Googlem). Stačí využít proměnnou $_SERVER["HTTP_REFERER"] a proměnnou $search
naplnit např. takto:
<?php if (preg_match('~^http://www\\.google\\..*[?&]q=([^&]+)~', $_SERVER["HTTP_REFERER"], $matches)) { $search = urldecode($matches[1]); //~ $search = iconv('utf-8', 'windows-1250', $search); // převod kódování $search = preg_replace('~all[^ ]+:.*~', '', $search); // odstranění operátorů all* $search = preg_replace('~([^ ]+:|-)[^ ]*~', '', $search); // odstranění operátorů a nechtěných slov $search = preg_replace('~[\\~+()]|\\bOR\\b~i', '', $search); // odstranění +~() a OR $search = preg_quote(htmlspecialchars($search), '~'); // escapování pro preg $search = preg_replace('~ +~', '|', $search); // nahrazení mezer znakem pro nebo $search = preg_replace('~"([^"]*)"~e', 'str_replace("|", "\\\\\\\\s+", "\\1")', $search); // zpracování uvozovek $search = "\\b($search)\\b"; // hledají se pouze celá slova } else { $search = preg_quote(htmlspecialchars($_GET["search"]), '~'); } ?>
Krapánek se to zesložitilo, ale mělo by to postihovat většinu funkcí, které Google pro vyhledávání nabízí. Obdobně by se zvýraznění výsledků vyhledávání dalo samozřejmě udělat i pro další vyhledávače.
Diskuse
Pachollini:
Pěkné, ale nemá to náhodou Google patentované? Co když po mně pak budou chtít 2$ za každou zobrazenou stránku s takovým zvýrazněním ;-)lukas:
Jsme v CR, ne v USA.Tomáš:
Kdyby to fungovalo ještě v Opeře a v Mozille, bylo by to naprosto super. A ono to určitě jde, jelikož to samotný google při vyhledávání v gmailu dělá.Hakuna:
No a nevíte náhodou o někám skriptu, který mi rozparsuje nějakou stránku s výsledky, např. vyhledávání, a potom pomoci REGEXP mi to vyhazi vysledky na moji stranku...? Napriklad pomoci preg_match_all ... prosím o radu a pomoc.Rozi:
už je to dávno ale v diskuzi na php.net sem našel:preg_replace("'(?!<.*?)$search(?![^<>]*?>)'si", '<span class="search-result">$0</span>', $text);
zvýrazní text všade krom html tagu ... odpadá odzvýraznění
Jakub Vrána
:
Řekl bych, že (?!<.*?) ve výrazu nedává smysl - znamená to, že $search nesmí začínat <, což ani nemůže, protože je ošetřený funkcí htmlspecialchars(). Možná měl původní autor na mysli lookbehind aserci, ale ta musí mít konstantní délku, navíc i tak by to bylo zbytečné. Nutnost ošetřit entity a vnitřky značek <option> a <textarea> zůstává.
Nicméně obrat (?![^<>]*?>) je pěkný.


Jakub Rychlý:
Jen pro úplnost.Z php manuálu:
<?php
$pattern = '(>[^<]*)('. quotemeta($_GET['search']) .')';
$replacement = '\\1<span class="search">\\2</span>';
$body = eregi_replace($pattern, $replacement, $body);
?>
Zvýrazní řetězce jen mezi jednotlivými tagy. Tedy nevkládá zvýraznění doprostřed tagu.
Jakub Vrána
:
Tento kód trpí několika neduhy:
1. Nezvýrazňuje text před první značkou (což může být potřeba, když nezvýrazňujeme celý dokument, ale např. jen jeho obsahovou část.
2. Zvýraznění dovoluje umístit i do značek <option> a <textarea>, kde je nepřípustné.
3. Zvýraznění dovoluje umístit i do entit, kde je také nepřípustné.
Všechny tyto problémy použitá funkce odzvyraznit() řeší.


Nechapu :-D:
jste blazni lidi... tohle pochopit tak si piskam =-O :-D jdu sprtat no
kriznik:
zdravim, sice se to primo netyka tohohle problemu, ale nenasel jsem lepsi misto kde se zeptat
resim replace ve vztahu k cestine a ne a ne ;(
napr. hledam "VST" a nahrazuju ho <span class>VST</span> (treba)
v message mam "vstřikování, vstrikovani, vst, vstš, vsts"
bohuzel se nahradi prvni, treti a ctvrte slovo > a melo by se resit pouze treti
jde tomu nejak zabranit, aby php nevidelo diakritiku jako dve ruzny?
vsechno je UTF-8, diky za tipy
<?php
$message = str_replace('\"', '"', mb_substr(@preg_replace('#(\>(((?>([^><]+|(?R)))*)\<))#se', "@preg_replace(\$forbiden, \$allowed, '\\0')", '>' . $message . '<'), 1, -1));
?>

lolek57:
Ahoj, použil jsem váš příklad a je to opravdu super, děkuji moc, jen bych se chtěl zeptat, když používám GET ve vyhledávání a zadám k vyhledání dvě slova (pes kočka), tak to udělá toto: pes+kočka. Ale poté už to nezvýrazní nic, když zadám jen jedno slovo tak ano.Děkuji předem za odpověď!
Online hry:
Jak použít fci preg_replace v případě, že chci nahrazovat např. ",< apod.? Vypisuje mi chybu No ending delimiter. Děkuji.
Karel Dytrych:
preg_replace('/</', 'cim nahradit', kde);
ale pokud je to jednoducha nahrada znak za znak, tak zkuste radsi str_replace();

Paja:
Jak je prosím možné, uvedený kód výše, upravit, aby zvýraznil všechny vyhledávané výrazy.Např.: Dnes byl krásný den.
Uvedený příklady zvýrazní pouze např. "krásný den". Ale potřeboval bych zvýraznit př.: "dnes den". Prostě všechna slova z vyhledávání.
Děkuji.
Diskuse je zrušena z důvodu spamu.

