Colorisation résultats de recherche

WRInaute occasionnel
Salut les amis :D

J'aurais besoin de vos lumières. Je viens de créer un moteur de recherche, et je souhaite coloriser les résultats.

J'ai tenté le coup en php, mais j'ai un souci, parce que j'arrive pas à filtrer totalement le texte contenu dans des balises html, ce qui me fout en l'air l'affichage => explode => foreach => dans la boucle, si plusieurs mots clé, plusieurs passages de l'analyseur => html dans html

Je suis en train de regarder avec javascript, mais idem, impossible de trouver un script qui filtre le texte contenu dans html, et je maîtrise pas assez les regex JS ou php pour arriver à faire quelque chose de propre.

Si vous avez connaissance d'un JS qui fonctionne bien de ce point de vue, ou d'une expression régulière en php qui permet de remplacer "color clé" par
Code:
<span class="color">color</span> <span class="autrecolor">clé</span>
sans que je me retrouve avec
Code:
<span class="<span class="color">color</span>">color</span>
au deuxième passage.

Je me prends la tête avec ça depuis un bon moment. Dans les deux cas, JS ou PHP, c'est au niveau du filtre que je me prends la tête.

Merci du coup de main si vous avez un bon tuyau.
+A+
 
WRInaute impliqué
euh je suis pas sur d'avoir bien compris mais dans le cas où tu souhaites changer la couleur des mots recherchés qui apparaissent dans les résultats le plus simple je pense c'est un str_replace du style : (script écrit à la volée j'ai pas vérifié le résultat)

Code:
$kw="xxx";
$txt="aaaa zz eeeee xxx rrrrr ffff";

echo str_replace($kw,"<font color=\"#ff0000\">".$kw."</font>",$txt);

et puis si t'as plusieurs mots dans ta recherche t'as juste à rajouter un explode et une boucle for
 
WRInaute occasionnel
Salut,

Merci de ta réponse tardive, moi qui me suis couché une heure avant et qui pensait être le dernier lol

Oui, mais j'ai déjà fait tout ça, le souci, c'est que le pointeur de la boucle passe plusieurs fois et modifie le texte contenu dans les balises html incluses au premier passage. Je n'arrive pas à faire un regex suffisamment fiable pour l'éviter, et le même problème se pose avec JS.

J'ai mis un exemple dans mon premier post de ce qui se passe. Inclusion de html dans le html à chaque itération de la boucle, si dans le code html inséré auparavant se trouve un des mots clé de la recherche.

J'ai réussi à généré un code couleur d'arrière plan en php unique par mot (qui reste le même), ainsi que son opposé pour le texte en surbrillance, pas évident (boucle foreach dans une boucle while), mais impossible de me débarasser de ce problème avec html.

Je crois que la seule solution serait un regex suffisament performant, mais je ne trouve pas seul :

Si tu trouve le mot clé "vacances", tu le remplace par <span class="color"> vacances </span> à la condition exclusive que le dit mot clé ne se trouve pas déjà entre des balises html

Voici mon code (qui se trouve dans une boucle while qui sort les résultats de la bdd)
Code:
			if ( isset ( $coloSyntaxique ) and $coloSyntaxique == true ) {

				foreach ( $separate as $key => $termeColor ) {

					if ( $testboucle == 1 ) { //-- On s'assure qu'on est au premier tout du while pour conserver les couleurs
						$couleur[$key] = rand_hexcolor();
						$motColore[$key] = '<span class="Style13" style="background-color: #' . strtoupper($couleur[$key]) . '; color:#'
						. strtoupper(inverse_hexcolor ( rand_hexcolor() ) ) . ';">' . $termeColor . '</span>';
					}

					//--On s'assure que l'on ne va pas remplacer les caractères html contenus dans $motColore[$key] => deformation affichage
					$$sit = eregi_replace ( $termeColor, $motColore[$key], $$sit );
					
				}

			}

J'ai essayé avec un
Code:
if ( $pos === false ) { $$sit = eregi_replace ( $termeColor, $motColore[$key], $$sit ); }
	$pos[$key] = strpos($$sit, $motColore[$key]); //-- Test si la chaine $motColore[$key] existe déjà

Sans succès
 
WRInaute accro
Je fais ça de la manière suivante (après avoir eu le genre de souci que tu as eu et m'être posé pas mal de question sur le sujet) :

Je lance un ob_start avant affichage du code html, que je récupère en fin de page avec ob_get_contents.

Et j'utilise cette fonction sur le contenu html récupéré avant de faire un echo :

Code:
function replace_occurence($getContentOfPage,$rechercheString,$idxTime)
{
	//on vérifie que la rexcherche ne contient que des caractères alphanumérique (espace accepté)
	$getContentOfPage = preg_replace('/alt="(.*)('.ClearString($rechercheString).')(.*)"/i',"alt=\"$1 ##".$idxTime."## $3\"",$getContentOfPage); 
	$getContentOfPage = preg_replace('/class="(.*)('.ClearString($rechercheString).')(.*)"/i',"class=\"$1 ##".$idxTime."## $3\"",$getContentOfPage); 
	$getContentOfPage = preg_replace('/id="(.*)('.ClearString($rechercheString).')(.*)"/i',"id=\"$1 ##".$idxTime."## $3\"",$getContentOfPage); 
	$getContentOfPage = preg_replace('/title="(.*)('.ClearString($rechercheString).')(.*)"/i',"title=\"$1 ##".$idxTime."## $3\"",$getContentOfPage); 
	$getContentOfPage = preg_replace('/src="(.*)('.ClearString($rechercheString).')(.*)"/i',"src=\"$1 ##".$idxTime."## $3\"",$getContentOfPage);
	$getContentOfPage = preg_replace('/href="(.*)('.ClearString($rechercheString).')(.*)"/i',"href=\"$1 ##".$idxTime."## $3\"",$getContentOfPage);  	
	$getContentOfPage = preg_replace("/alt='(.*)(".ClearString($rechercheString).")(.*)'/i",'alt=\'$1 ##'.$idxTime.'## $3\'',$getContentOfPage); 
	$getContentOfPage = preg_replace("/class='(.*)(".ClearString($rechercheString).")(.*)'/i",'class=\'$1 ##'.$idxTime.'## $3\'',$getContentOfPage); 
	$getContentOfPage = preg_replace("/id='(.*)(".ClearString($rechercheString).")(.*)'/i",'id=\'$1 ##'.$idxTime.'## $3\'',$getContentOfPage); 
	$getContentOfPage = preg_replace("/title='(.*)(".ClearString($rechercheString).")(.*)'/i",'title=\'$1 ##'.$idxTime.'## $3\'',$getContentOfPage); 
	$getContentOfPage = preg_replace("/src='(.*)(".ClearString($rechercheString).")(.*)'/i",'src=\'$1 ##'.$idxTime.'## $3\'',$getContentOfPage);
	$getContentOfPage = preg_replace("/href='(.*)(".ClearString($rechercheString).")(.*)'/i",'href=\'$1 ##'.$idxTime.'## $3\'',$getContentOfPage);  
	$getContentOfPage = preg_replace('/'.ClearString($rechercheString).'/i','||'.$idxTime.'||',$getContentOfPage);   
	$getContentOfPage = str_replace('||'.$idxTime.'||',"<b class='searchresult'>".ClearString($rechercheString)."</b>",$getContentOfPage);  
	$getContentOfPage = str_replace('##'.$idxTime.'##',ClearString($rechercheString),$getContentOfPage); 
	return $getContentOfPage;
}

Clearstring est une fonction de nettoyage de caractères pourris (en provenance de word par exemple). Ma fonction me permet de passer en revu tout le code HTML, de fair eun premier replace de chaque occurence de mon mot recherché par un code spécifique, en fonction du cas où le mot en question doit ou pas être remplacé (selon s'il est inclus dans un jeu de balise où je ne dois pas inclure du html ou pas), puis je fais les replace nécessaire pour ne modifier que les mots qui doivent être mis en avant.

J'avoue ce n'est peut-être pas parafit, il y a sûrement d'autres cas à gérer mais pour el moment c'est pile poil ce dont j'avais besoin.
 
WRInaute occasionnel
Salut et merci de ton aide.

Je viens de tester, même problème, les termes sont encore remplacés dans le code html.

La recherche se fait dans un premier temps en ajax avec auto complétion, le nombre de réponses s'affiche sous le champ de recherche texte.
Si le nombre de réponse se trouve entre 1 et 100 (au delà, j'affiche "trop de réponses - précisez"), alors ajax retourne en réponse dans un <div> un formulaire avec le champ hiden "q" qui contient les mots clé de la recherche fructueuse (en terme de nbre de résultats), pour partir en $_GET formaté correctement (url_encode) lors de la validation (en JS uniquement pour éviter que les moteurs indexent n'importe quoi).

Je ne filtre donc pas les mots de deux caractères, il font intégralement partie de la recherche car l'internaute voit pendant la saisie le nombre de réponses. C'est donc un choix.

Résultat, si tu as class="" dans ton code html et que le type tape "a la mer" le A de clAss sera remplacé et tout part en vrille.

Je voudrais trouver une solution de regex qui indique de ne pas remplacer pour être précis tout ce qui se trouve entre les balises <span></span>

Je n'utilise pas d'autres balises que ces deux là, ça doit bien être possible, mais pour l'instant je fais choux blanc

Merci encore du coup de main, je garde ta fonction sous le coude pour autre chose éventuellement, en bon bricoleur, ça servira un jour :wink:
 
WRInaute accro
Le truc c'est que j'ai en effet localisé l'effet de ma fonction à une zone de contenu dont je maîtrise le html.
 
WRInaute accro
Pour info j'ai repris tout à 0 en partant de la fonctionnalité de ce type que propose SPIP (dans ecrire/inc/surligne.php) . Et ca a l'air d'être nettement plus efficace et abouti que ce que j'avais initialement réalisé.
 
WRInaute accro
En fait SPIP propose ce genre de fonctionnalité dans leur moteur. Je uis en train de repartir de ça et d'adapter à mon cas, amis je n'ai pas encore fini. Les fonctions de SPIP utilisées pour surligner (avec pas mal de regexp bien fichues) sont dans le dossier de SPIp (je pars d'une version 1.9.2) cité dans mon message au-dessus.
 
WRInaute occasionnel
Ah ok, merci. Je vais regarder quand j'aurai un moment, mais c'est pas simple cette affaire pour coloriser des mots clé proprement, en plus des soucis d'encodage des accents (ajax en utf8, $_GET en encodage url, doctype de la page...), faut être patient.

Je m'en sors, mais parfois c'est plus que long.
 
WRInaute impliqué
ok dans ce cas je pencherai peut etre pour un preg_replace avec une regex du style : (pour reprendre le nom des variables de l'exemple suivant) :

Code:
"[^>]".$kw."[^<]"
 
WRInaute occasionnel
Y a de l'idée, mais à priori c'est pas ça. Merci.

Dans mon cas, il faut éviter de remplacer les mots clé dans les expressions suivantes :

Code:
<span class="Style13" style="background-color: #' . strtoupper($couleur[$key]) . '; color:#' . strtoupper(inverse_hexcolor ( rand_hexcolor() ) ) . ';">' . $termeColor . '</span>

On va prendre un cas concret :

Prenons par exemple les mots clé "vacances la mer" pour une recherche dans un texte "vacances au bord de la mer pas cher"

On utilise <?php explode(); ?> qui nous place les 3 mots ( "a" - "la" - "mer") dans un array, que l'on va parcourir avec foreach, comme dans le code que j'avais posté plus haut.

Première itération de la boucle, dans le texte source on remplace le mot clé "vacances" par le substitut qui va le coloriser <span class="Style13" style="background-color: #FFF; color:#000;">vancances</span> et on obtient :
Code:
<span class="Style13" style="background-color: #FFF; color:#000;">vancances</span> au bord de la mer pas cher

Deuxième itération de la boucle, dans le texte, on devrait obtenir:
Code:
<span class="Style13" style="background-color: #FFF; color:#000;">vancances</span> au bord de <span class="Style13" style="background-color: #FF0; color:#DD0;">la</span> mer pas cher

Or le souci, c'est que le terme la sera remplacé y compris dans le code html initial et on va obtenir :
Code:
<span c<span class="Style13" style="background-color: #FF0; color:#DD0;">la</span>ss="Style13" style="background-color: #FFF; color:#000;">vancances</span> au bord de <span class="Style13" style="background-color: #FF0; color:#DD0;">la</span> mer pas cher

Et là c'est le drame. Il faut donc trouver un regex qui interdit tout remplacement de code lorsque l'expression clé détectée se trouve entre les balises <span class="Style13" style="background-color: #FFF; color:#000;">Expression clé</span>

Donc entre les balises <span></span> finalement, puisqu'il n'y en a pas d'autres que celles ci dans le texte, qui est nettoyé avant d'être stocké en base de donnée.

Inutile de faire un truc complexe qui détecte tout trace de html, mais unique du texte contenu entre ces balises, y compris d'autres codes html comme class="" ou background-color: #FFF;

J'espère que c'est clair, mais cette expression ou regex miraculeuse à utiliser avec eregi_replace(), je ne la trouve pas.

Merci
 
WRInaute impliqué
ok je vois ton probleme... bon courage ;)

mdr

nan je vais y réfléchir aujourd'hui...

A première vue j'ai peut être une idée avec une fonction récursive et des split
 
WRInaute impliqué
emballé c'est pesé :

Code:
<?php

function setColorz($kws,$txt,$bgcol,$col) {
    $swp1=explode(" ",$kws);
    $swp2=preg_split("/([^\w])+/",$txt,-1,PREG_SPLIT_DELIM_CAPTURE);
    $ret="";
    for ($i=0;$i<count($swp2);$i++) {
        $isKW=false;
        for ($j=0;$j<count($swp1);$j++) {
            if ($swp2[$i]==$swp1[$j]) { $isKW=true; }
        }
        if ($isKW) {
            $ret.="<span class=\"Style13\" style=\"background-color: ".$bgcol."; color:".$col.";\">".$swp2[$i]."</span>";
        } else {
            $ret.=$swp2[$i];
        }
    }
    return $ret;
}


$kws="vacances à la mer";
$txt="vacances au bord de la mer pas cher";

echo setColorz($kws,$txt,"#FFF","#000");


?>
 
WRInaute occasionnel
Oups, désolé, j'avais pas vu ta réponse, je n'ai pas reçu l'alerte...

Je vais regarder, je te tiens au courant, merci de ton aide.
 
WRInaute occasionnel
C'est parfait !!

Tout fonctionne impeccable, je te remercie énormément pour ce coup de main providentiel RiPSO

Merci bcp

J'ai perdu 2 jours entiers à me prendre la tête avec cette connerie, sans succès.

Heureusement que tu as eu cette idée, j'étais sur le point de laisser tomber.
 
WRInaute impliqué
Ah cool ça fait plaisir :) je désespérerais d'avoir fais cette fonction pour rien...

Pour info chez moi je l'ai testée avec une balise font plutôt que span, j'ai laissé span vu que c'était ce que tu voulais.

Bon bin c'est cool si ça fonctionne, a++ ;)
 
WRInaute occasionnel
Je l'ai modifiée un peu aussi, j'ai rajouter un <strong> pour le référencement de mes résultats de recherche, comme je doute que pour l'instant les moteurs prennent bien en compte les CSS.

Par contre, j'ai pas réussi à générer une couleur différente pour chaque mot, qui reste toujours la même dans la liste de résultats.

Je l'avais pensé comme ça au départ, mais ça ne va pas, parce que la fonction est appelée autant de fois qu'il y a de résultats dans une boucle while suite à la requête SQL.

Encore merci pour ton aide, tu dois savoir ce que c'est que de planter des heures sur un bout de code :)
 
WRInaute impliqué
oui tinkiet je sais ce que c'est d'être planté :d c'est pour ça que je t'ai fais ta fonction, je savais que ça ne me prendrai que quelques minutes, c'est pas grand chose comparé au mal de crane que l'on a a force de réfléchir :)

pour ton changement de couleur je pensais à ajouter un tableau de couleurs prédéfinies genre :

Code:
$tabcol=array("#ff0000","#00FF00","#0000FF","#FF8800");

et ensuite dans ta boucle t'as deux solutions soit tu appelles ca avec un :

Code:
$tabcol[$i%count($tabcol)]

Soit tu créé une variable, par exemple $inc, qui s'incrémentera a chaque passage :
Code:
$inc=0;

//et après dans la boucle tu appelle ton tabcol avec :

$tabcol[$inc];

//et enfin de boucle il ne faut surtout pas oublier de remettre inc a 0 quand elle a fait un tour :
$inc%=count($tabcol);

J'ai sorti ça de tête sans vérification donc y'aura peut être une erreur :? mais normalement ça devrait le faire
 
WRInaute occasionnel
J'ai opté pour la seconde solution, la première ne fonctionnait pas.

En fait, je traite plusieurs portions de texte (plusieurs champs de BDD successivement si tu préfères) et la première ne me sortait que 2 couleurs changeantes pour un même terme.

La seconde solution n'est pas parfaite, mais pas loin. En fait, j'ai quelques écarts de couleur pour la partie texte la plus longue, qui est environ 10 fois supérieure aux autres champs, mais le résultat est sympa et tout à fait acceptable.

Un grand merci pour ce coup de main bienvenue, c'est vraiment sympa. Tu me fais gagner un temps précieux :D

Si je peux faire quelque chose pour toi, n'hésites pas.
 

➡️ Offre MyRankingMetrics ⬅️

pré-audit SEO gratuit avec RM Tech (+ avis d'expert)
coaching offert aux clients (avec Olivier Duffez ou Fabien Faceries)

Voir les détails ici

coaching SEO
Discussions similaires
Haut