[PHP] moteur de recherche interne, requête insensible aux accents

Consultez la formation à Google Analytics de WebRankInfo / Ranking Metrics

leica69
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 30
Inscription: 25 Oct 2004

[PHP] moteur de recherche interne, requête insensible aux accents

Message le Mar Avr 07, 2009 21:16

Bonjour,
je suis en train de faire un moteur de recherche interne pour mon site.

1/ Je récupère le mot cle de recherche transmis par formulaire:
Code: Tout sélectionner
$recherche = $_POST['rech'];
$recherche = trim($recherche);


2/ je fais une recherche dans ma base de données (PHP5, utf8_unicode_ci)
Je souhaite que les mots recherché soient surlignés dans l'affichage final
Code: Tout sélectionner
$requete="SELECT * FROM table WHERE champ1 LIKE '%$recherche%' OR champ2 LIKE '%$recherche%''";
$resultat=mysql_query($requete) or die ("Problème lors de la requête. Erreur: ".mysql_error());

while($ligne=mysql_fetch_array($resultat)){
   $valeur1 = $ligne[champ1];
   $valeur2 = $ligne[champ2];
   
   // recherche et remplacement du mot de la recherche pour l'entourer d'un <span> de mise ne forme
   $pattern = '('. quotemeta($recherche) .')';
   $replacement = "<span class='selection'>\\1</span>";
   $valeur1 = eregi_replace($pattern, $replacement, $valeur1);
   $valeur2  = eregi_replace($pattern, $replacement, $valeur2);

   // Affichage du résultat mis en forme
   echo "<p>$valeur1 </p>";
   echo "<p>$valeur2 </p>";
}


Maintenant, je vous explique mon souci:
Quand je fais la recherche SQL, elle est insensible aux accents.
Quand je fais la recherche PHP, elle est insensible à la casse mais sensible aux accents.

Si je fais une recherche sur "pre":
- SQL va me retourner les enregistrements contenant "précision", "âpre", "premier",...
- PHP va uniquement surligner "âpre", "premier"

Mon problème est une incohérence des recherches. Je vais avoir des champs de texte sans rien de surligné, c'est déroutant pour l'utilisateur (et pour moi).

Je souhaite avoir deux recherches cohérentes:
Soit tout insensible aux accents // Soit tout sensible aux accents

J'ai essayé de remplacer tous les caractères accentués par leur équivalent sans accent. Le pb est que je me retrouve avec un texte de résultat sans les accents. Je veux un texte juste (accentué) en retour.

J'espère que qqn pourra m'aider!!

D'avance, merci,
Antonio


forty
WRInaute passionné
WRInaute passionné
 
Messages: 1701
Inscription: 30 Oct 2008

Re: [PHP] moteur de recherche interne, requête insensible aux accents

Message le Mar Avr 07, 2009 22:43

tu peux utiliser un code comme celui ci pour transformer ta mot recherché en regex. ca transforme par exemple "Eléphant" en "[eèéêë]l[eèéêë]phant" pour alimenter ton partern
Code: Tout sélectionner
function regexAccents($chaine) {
   $accent = array('a','à','á','â','ã','ä','å','c','ç','e','è','é','ê','ë','i','ì','í','î','ï','o','ð','ò','ó','ô','õ','ö','u','ù','ú','û','ü','y','ý','ý','ÿ');
   $inter = array('%01','%02','%03','%04','%05','%06','%07','%08','%09','%10','%11','%12','%13','%14','%15','%16','%17','%18',
                       '%19','%20','%21','%22','%23','%24','%25','%26','%27','%28','%29','%30','%31','%32','%33','%34','%35');
   $regex = array('[aàáâãäå]','[aàáâãäå]','[aàáâãäå]','[aàáâãäå]','[aàáâãäå]','[aàáâãäå]','[aàáâãäå]',
                        '[cç]','[cç]',
                        '[eèéêë]','[eèéêë]','[eèéêë]','[eèéêë]','[eèéêë]',
                        '[iìíîï]','[iìíîï]','[iìíîï]','[iìíîï]','[iìíîï]',
                        '[oðòóôõö]','[oðòóôõö]','[oðòóôõö]','[oðòóôõö]','[oðòóôõö]','[oðòóôõö]','[oðòóôõö]',
                        '[uùúûü]','[uùúûü]','[uùúûü]','[uùúûü]',
                        '[yýýÿ]','[yýýÿ]','[yýýÿ]','[yýýÿ]');
   $chaine = str_ireplace($accent, $inter, $chaine);
   $chaine = str_replace($inter, $regex, $chaine);
   return $chaine;
}

leica69
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 30
Inscription: 25 Oct 2004

Re: [PHP] moteur de recherche interne, requête insensible aux accents

Message le Mer Avr 08, 2009 0:39

Merci pour l'astuce. Théoriquement ça devrait fonctionner. Mais malheureusement ce n'est pas le cas pour moi.
J'ai fait une requête simplifiée utilisant ton idée, histoire d'identifier le problème.

ma chaîne de départ
Code: Tout sélectionner
$desc = "poire très stress tresse tréssaillir(SIC)";


la chaîne à mettre en gras:
Code: Tout sélectionner
$pattern = "(tr[eèé])"; // qui devrait correspondre à tre, trè, tré


La substitution pour mettre en gras
Code: Tout sélectionner
$replacement = "<b>\\1</b>";


le remplacement
Code: Tout sélectionner
$test3 = eregi_replace($pattern, $replacement, $desc);
echo "$test3";


et j'obtiens
dans le code source: poire <b>tr�</b>�s s<b>tre</b>ss <b>tre</b>sse <b>tr�</b>�ssaillir(SIC)
à l'affichage: poire tr��s stress tresse tr��ssaillir(SIC)

(ce qui est étonnant c'est que le caractère soit doublé. Le gras fonctionne mais n'est pas affiché dans ce dernier exemple)
les caractères d'erreur sont des losanges avec des ? à l'intérieur.

Je suis en UTF-8 dans tout le processus et mon navigateur (firefox) est correctement réglé.

Uni idée de solution??


forty
WRInaute passionné
WRInaute passionné
 
Messages: 1701
Inscription: 30 Oct 2008

Re: [PHP] moteur de recherche interne, requête insensible aux accents

Message le Mer Avr 08, 2009 7:55

c'est sûrement a cause de l'utf-8. comme les lettres accentuées sont sur deux caractères les [] matchent toutes les lettres.
essaye de remplacer [eèé] par (e|è|é)

leica69
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 30
Inscription: 25 Oct 2004

Re: [PHP] moteur de recherche interne, requête insensible aux accents

Message le Mer Avr 08, 2009 8:52

Ca ne fonctionne toujours pas.

Je joue un peu avec l'encodage/décodage UTF-8 / ISO-8859-1 pour essayer de contourner le problème mais je bloque encore.
Code: Tout sélectionner
$desc = "poire très stress tresse tréssaillir(SIC)";
$desc = htmlentities($desc,ENT_NOQUOTES, "UTF-8");
//desc: poire tr&egrave;s stress tresse tr&eacute;ssaillir(SIC)

$pattern = "(tr[è|e|é])";
$pattern = htmlentities($pattern,ENT_NOQUOTES, "UTF-8");
//pattern: (tr[&egrave;|e|&eacute;])

$replacement = "<b>\\1</b>";

$test3 = eregi_replace($pattern, $replacement, $desc);


j'obtiens ça dans le code source de la page

Code: Tout sélectionner
poire <b>tr&</b>egrave;s s<b>tre</b>ss <b>tre</b>sse <b>tr&</b>eacute;ssaillir(SIC)

Ce qui me surprend c'est que seul le premier "caractère" (&) du caractère accentué soit dans la balise <b>


forty
WRInaute passionné
WRInaute passionné
 
Messages: 1701
Inscription: 30 Oct 2008

Re: [PHP] moteur de recherche interne, requête insensible aux accents

Message le Mer Avr 08, 2009 10:25

tu ne peux pas mettre [&egrave;|e|&eacute;] car les crochets autorisent les caractères & e g r a v c u t et |
pour indiquer des chaînes il faut mettre entre parenthèse comme indiqué dans le précédent message : (&egrave;|e|&eacute;)

leica69
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 30
Inscription: 25 Oct 2004

Re: [PHP] moteur de recherche interne, requête insensible aux accents

Message le Mer Avr 08, 2009 12:43

Je n'avais pas vu les parenthèses!!!!!
Ca fonctionne! J'ai quand même du jongler avec les UTF-8 et ISO

Voici le code, si ça peut aider qqn un jour:

Code: Tout sélectionner
function regexAccents($chaine) {
   $accent = array('a','à','á','â','ã','ä','å','c','ç','e','è','é','ê','ë','i','ì','í','î','ï','o','ð','ò','ó','ô','õ','ö','u','ù','ú','û','ü','y','ý','ý','ÿ');
   $inter = array('%01','%02','%03','%04','%05','%06','%07','%08','%09','%10','%11','%12','%13','%14','%15','%16','%17','%18','%19','%20','%21','%22','%23','%24','%25','%26','%27','%28','%29','%30','%31','%32','%33','%34','%35');
   $regex = array('(a|à|á|â|ã|ä|å)','(a|à|á|â|ã|ä|å)','(a|à|á|â|ã|ä|å)','(a|à|á|â|ã|ä|å)','(a|à|á|â|ã|ä|å)','(a|à|á|â|ã|ä|å)','(a|à|á|â|ã|ä|å)',
'(c|ç)','(c|ç)',
'(è|e|é|ê|ë)','(è|e|é|ê|ë)','(è|e|é|ê|ë)','(è|e|é|ê|ë)','(è|e|é|ê|ë)',
'(i|ì|í|î|ï)','(i|ì|í|î|ï)','(i|ì|í|î|ï)','(i|ì|í|î|ï)','(i|ì|í|î|ï)',   '(o|ð|ò|ó|ô|õ|ö)','(o|ð|ò|ó|ô|õ|ö)','(o|ð|ò|ó|ô|õ|ö)','(o|ð|ò|ó|ô|õ|ö)','(o|ð|ò|ó|ô|õ|ö)','(o|ð|ò|ó|ô|õ|ö)','(o|ð|ò|ó|ô|õ|ö)',         '(u|ù|ú|û|ü)','(u|ù|ú|û|ü)','(u|ù|ú|û|ü)','(u|ù|ú|û|ü)',
'(y|ý|ý|ÿ)','(y|ý|ý|ÿ)','(y|ý|ý|ÿ)','(y|ý|ý|ÿ)');
   $chaine = str_ireplace($accent, $inter, $chaine);
   $chaine = str_replace($inter, $regex, $chaine);      
   return $chaine;
}

$recherche = $_POST['rech'];
$recherche = trim($recherche);
      
$pattern = '('. $recherche .')';
$pattern = regexAccents($pattern);
$pattern = htmlentities($pattern,ENT_NOQUOTES, "ISO-8859-1");
   
$replacement = "<span class='selection'>\\1</span>";

if($_POST['rech'] != ""){
   if (strlen($_POST['rech']) >= 3){
      echo "<p>Résultat de la recherche pour <strong>$recherche</strong></p>";
               
      $requete="SELECT * FROM table WHERE champ1 LIKE '%$recherche%' OR champ2 LIKE '%$recherche%' ";
      $resultat=mysql_query($requete) or die ("Problème lors de la requête. Erreur: ".mysql_error());
            
      if (mysql_num_rows($resultat) > 0){
         echo "\n<h2>Huiles essentielles</h2>\n";
      }
                  
      while($ligne=mysql_fetch_array($resultat)){
         $val1 = $ligne[champ1];
         $val2 = $ligne[champ2];
                  
         $val1 = html_entity_decode(eregi_replace($pattern, $replacement, htmlentities($val1,ENT_NOQUOTES, "ISO-8859-1")));
         $val2 = html_entity_decode(eregi_replace($pattern, $replacement, htmlentities($val2,ENT_NOQUOTES, "ISO-8859-1")));
                  
         if(preg_match("/".$pattern."/i",$val1 ) > 0 OR preg_match("/".$recherche."/i",$val1 ) > 0){
            echo "\n$val1 ";
         }

         if(preg_match("/".$pattern."/i",$val2 ) > 0 OR preg_match("/".$recherche."/i",$val2 ) > 0){
            echo "\n$val2 ";
         }
               
      } else {
         echo "\n<p>Votre recherche doit comporter au moins trois caractères</p>\n";
      }
            
   } else {
      echo "\n<p>Veuillez saisir un mot pour effectuer votre recherche.</p>\n";
   }
}


blman
WRInaute accro
WRInaute accro
 
Messages: 3077
Inscription: 5 Sep 2003

Re: [PHP] moteur de recherche interne, requête insensible aux accents

Message le Mer Avr 08, 2009 12:51

Réponse hors sujet, mais tu gagnerais en performance en faisant ta requête SQL ainsi :

Code: Tout sélectionner
$requete="SELECT * FROM table WHERE CONCAT(champ1," ",champ2) LIKE '%$recherche%'";


Les OR sont vraiment gourmand en ressources. En concaténant tes champs, tu gagne en performance.

leica69
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 30
Inscription: 25 Oct 2004

Re: [PHP] moteur de recherche interne, requête insensible aux accents

Message le Mer Avr 08, 2009 13:18

Cooool! Merci

C'est d'autant plus pertinent que je fais ma recherche sur 5 champs. Ca me permet aussi de faire un seul LIKE.
Encore Merci

leica69
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 30
Inscription: 25 Oct 2004

Re: [PHP] moteur de recherche interne, requête insensible aux accents

Message le Mer Avr 08, 2009 17:38

Je me rends compte d'un souci supplémentaire.

Une partie du texte de ma base contient du formatage HTML <strong>Nom</strong>, par exemple.
Comment faire pour que ma recherche ne prenne pas en compte mes balises?

Pour rappel, j'ai ceci:
Code: Tout sélectionner
$search = '('. $search  .')';
$search = regexAccents($search); // voir posts précédents, c'est pour être insensible aux accents
$search = htmlentities($search,ENT_NOQUOTES, "ISO-8859-1");

$valeur = html_entity_decode(eregi_replace($search, $replacement, htmlentities($valeur,ENT_NOQUOTES, "ISO-8859-1")));


Je dois modifier mon critère de recherche la bonne syntaxe. Pour l'instant, j'en suis là:
Code: Tout sélectionner
$search = '([^<][\S]*)('. $search .')([\S]*[^>])';

Dans ce cas précis, si je recherche "tron", c'est la catastrophe!!!


forty
WRInaute passionné
WRInaute passionné
 
Messages: 1701
Inscription: 30 Oct 2008

Re: [PHP] moteur de recherche interne, requête insensible aux accents

Message le Mer Avr 08, 2009 18:03

il y a peut-être une piste avec la fonction preg_replace_callback pour extraire tout ce qui n'est pas balise et faire ensuite ton replace mais je ne suis pas spécialiste


blman
WRInaute accro
WRInaute accro
 
Messages: 3077
Inscription: 5 Sep 2003

Re: [PHP] moteur de recherche interne, requête insensible aux accents

Message le Mer Avr 08, 2009 18:24

Leica69,

personnellement, j'ajouterais un champs à ma table qui contient une chaine avec tous tes champs déjà concaténés et formaté (sans balise HTML, sans accent, tout en minuscule et sans les mots qui peuvent être des stop words). Tu indexera ton contenu dans ce champ à chaque fois que tu met à jour la ligne concernée dans ta table.

Tu y gagnera énormément en ressource et en simplicité au niveau de la recherche. Tu pourrais par exemple l'indexer en FULLTEXT pour gagner en pertinence ou plus facilement le charger en mémoire si tu veux faire de la correction orthographique.

Parce que là, en voyant la manière dont tu fais la recherche et comment tu la traite en sortie, à mon avis, tu es mal parti. Essaye de traiter tes données au maximum en entrée (indexation de tes keywords)

PS : sinon tu a la fonction strip_tags() en PHP pour retirer les balises HTML : http://fr2.php.net/strip-tags

leica69
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 30
Inscription: 25 Oct 2004

Re: [PHP] moteur de recherche interne, requête insensible aux accents

Message le Mer Avr 08, 2009 18:40

Salut,
Je m'en suis sorti avec strip_tags()

C'est vrai que pour la suite, si je complexifie le traitement de la base, je devrais passer par une colonne qui regroupera mes entrées.

En tout cas, merci pour ta solution.


Si vous avez aimé cette discussion, partagez-la sur vos réseaux sociaux préférés :

Formation recommandée sur ce thème :

Formation Google Analytics : en 2 jours, apprenez comment exploiter l'essentiel des possibilités de l'outil de mesure d'audience de Google. Formation animée par les experts Google Analytics de Ranking Metrics.

Tous les détails sur le site Ranking Metrics : programme, prix, dates et lieux, inscription en ligne.

Lectures recommandées sur ce thème :



Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 1 invité