A keresés megvalósítása még viszonylag egyszerű és kézenfekvő feladat annak, aki kicsit ért az SQL-hez. Feltéve persze, hogy a keresendő információt is SQL adatbázisban tárolja. De biztos mindenki látott már olyant, hogy a találatok ki voltak emelve valamilyen színes háttérrel. Erre írok egy nem tökéletes, de használható megoldást. Amiből már el lehet indulni egy komolyabb felé is.
A keresés még rendben van általában. De az ember szereti látni, hogy amire rákeresett, az mégis a talált szövegben hol van. Lehet persze a böngésző beépített kereső funkcióját is használni, ami firefox-ban a CTRL+F billentyű kombinációval is elérhető, de megspórolhatunk a felhasználónak ennyi többletmunkát.
Felvázolom az alap problémát.
Ha SQL adatbázist használunk, akkor amennyiben "_ci" végződésű karakterkészlettel rendelkező táblát használunk, a találatokban az "a", "A", "á" és "Á" is ugyanannak a karakternek számít. Ez jó is. Szerintem ezt az előnyt nem érdemes feláldozni. Tehát marad az a verzió, hogy a kijelölést is ennek megfelelően végezzük. Enélkül elég volna az str_replace() függvény használata. Most viszont a preg_replace() -re lesz szükség.
A megoldás első lépései:
Teszt szövegnek a már megszokott általános és értelmetlen kifejezést fogom használni, amiben benne van az összes magyar ékezetes karakter is. Nevezzük $msg -nek
$msg = "Árvíztűrő tükörfúrógép <b>ÁRVÍZ</b>TŰRŐ TÜKÖRFÚRÓGÉP";
Előfordulhat, hogy html is van a szövegben. Ezt benne hagyni bonyolultabb móka lenne, ezért a találatban minden html tag el lesz távolítva. És a puszta szöveg lesz megjelenítve a kiemeléssel. Nézzük hogy fog kinézni az űrlap. Mert hát az is kell.
<head>
<title>Kereső</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<style type="text/css">
body {
background: #446699;
color: white;
}
a {
color: white;
}
</style>
</head>
<body>
<form action="" method="post">
Keresett kifejezés:
<input type="text" name="search" />
<input type="submit" value="Keres" />
</form>
Üzenet: <?php print $msg; ?>
</body>
</html>
A keresendő kifejezés tehát a $_POST['search'] változóban lesz. Viszont szerverbeállítástól függően lehet, hogy az idézőjelek backslashelve lesznek. Ezt a beállítást a get_magic_quotes_gpc() -vel kérdezhetjük le. És amennyiben be van kapcsolva, a stripslashes() függvénnyel törölhetjük a \ jeleket.
if (get_magic_quotes_gpc())
{
$search = stripslashes($search);
}
A preg_replace hasonlóan az str_replace -hez 3 paramétert vár minimum. Azt, amit le akarunk cserélni, azt, amire cserélni akarjuk és azt, amiben. Az első két paraméter tömb is lehet. Akkor azonos sorrendben kell felsorolni a két tömbben amit és amire cserélni szeretnénk. Erre is szükség lesz, de előbb megmutatom milyen egyszerű is a kiemelés.
$msg = preg_replace('/'.$search.'/iu',"<span style='background-color: #000066;'>\\0</span>",strip_tags($msg));
A strip_tags függvény felelős a html tag-ek eltávolításáért. Így egy szimpla szövegben történik a kiemelés.Második paraméterben adjuk meg, mire kel cserélni a találatokat. Itt a \\0 jelenti a teljes mintát. Legyen elég a példához most ennyi. Akit érdekel, utánanézhet a függvénynek a php.net -en. Az első paraméter viszont érdekesebb. "/" jelek között van maga a keresendő minta. Utána az "i" módosító mondja meg, hogy a kis és nagybetűk különbsége ne számítson. Tehát a keresés itt is Case Sensitive lesz, mint az sql lekérdezésnél. Az "u" módosító az utf-8 karakterkódolás használata miatt kell. Mert másképp a unicode karakterekkel nem működne a függvény helyesen. Persze aki nem unicode -ot használ, elhagyhatja ezt a módosítót.
Igen ám, de ha a $search változóban megmarad a keresett kifejezés, akkor az ékezetes és nem ékezetes karakterek különbözni fognak, pedig adatbázisban ez nincs így. Ezért ennek a tartalmát is át kell konvertálni egy olyan mintára, ahol az egyes karaktereket karaktercsoportokká (atomokká) alakítjuk. Az atomok szögletes zárójelben vannak, és a bennük felsorolt karakterek úgymond vagy kapcsolatban fognak állni. Tehát a "találat" szóban ha az a és á betűket keressük, akkor így kellene megadni a mintát: [aá]
Ennek megfelelően tehát definiáljuk a karaktercsoportokat.
'[aá]',
'[eé]',
'[oóöő]',
'[ií]',
'[uúüű]'
);
Külön sorba tettem minden csoportot az áttekinthetőség kedvéért. Az egy sorban levő karakterek a zárójelben így azonosnak fognak számítani. Ha valaki új karaktert szeretne egy csoporthoz adni, semmi akadálya. Ez volt az, amire cserélni kell. De Így a keresendő kifejezésben a magánhangzókat mintákra cseréljük. Azonban azt, hogy mely magánhangzókat cseréljük ezekre a mintákra, érdekes módon ugyanezzel a mintával kell definiálni. Csak kell köré a '/' jel és a unicode módosító.
$from = array_map(create_function('$v', 'return "/$v/u";'),$to);
Az array_map függvény első paramétere egy függvény neve. Vagy jelen esetben egy névtelen függvény, amit a create_funcion hoz létre. Ennek első paramétere a létrehozandó függvény paraméterlistája vesszővel elválasztva. Második paraméter pedig a függvény tartalma. Az aposztróf itt szándékos. Mert így a változókat nem próbálja meg kiértékelni az értelmező, hanem egyszerű szövegként kezeli. Végül az array_map második paramétere egy tömb, aminek minden elemét át kell adni az első paraméterben megadott függvénynek. Így lesz minden eleme a $from változónak "/$v/u" alakú, ahol $v egy-egy elem a $to tömbből. Aki ezt bonyolultnak látja, az adja meg nyugodtan kézzel:
'/[aá]/u',
'/[eé]/u',
'/[oóöő]/u',
'/[ií]/u',
'/[uúüű]/u'
);
És most jön a végső pattern létrehozása.
$search =preg_replace($from,$to,preg_quote($search));
A preg_quote felel azért, hogy minden olyan karakter elé \ jelet tegyen a $search változóban, amik valamilyen mintát jelölnének. Enélkül például a [teszt] szóra keresésnél problémák lennének a kapcsos zárójelek miatt. Ekkor a $search változóban ha a "árvíz" szóra kerestem, a következő lesz: [aá]rv[ií]z
A teljes forrás tehát a következő:
$msg = "Árvíztűrő 'tükörfúrógép <b>ÁRVÍZ</b>TŰRŐ TÜKÖRFÚRÓGÉP";
if (isset($_POST['search']) and trim($_POST['search']) != '')
{
$search = $_POST['search'];
if (get_magic_quotes_gpc())
{
$search = stripslashes($search);
}
$to = array(
'[aá]',
'[eé]',
'[oóöő]',
'[ií]',
'[uúüű]'
);
$from = array_map(create_function('$v', 'return "/$v/u";'),$to);
$search =preg_replace($from,$to,preg_quote($search));
$msg = preg_replace('/'.$search.'/iu',"<span style='background-color: #000066;'>\\0</span>",strip_tags($msg));
}
?>
<html>
<head>
<title>Kereső</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<style type="text/css">
body {
background: #446699;
color: white;
}
a {
color: white;
}
</style>
</head>
<body>
<form action="" method="post">
Keresett kifejezés:
<input type="text" name="search" />
<input type="submit" value="Keres" />
</form>
Üzenet: <?php print $msg; ?>
</body>
</html>
A program kipróbálható: DEMO megtekintése
Egyúttal a forráskódra is található link a DEMO-ban is.
Hozzászólások
Valahonnét olyan ismerős. :D
Valahonnét olyan ismerős. :D De még mindig jó.
Ha elköltözik az oldalam, majd nyáron beépítek egy keresőt belé, ugyanezt fogja használni. :)