Surligner un mot dans un texte HTML

Tous les benchmarks, vos résultats, vos tests.
Vos programmes, vos conseils logiciel
Votre matos, vos problèmes
Avatar de l’utilisateur
Aurelienazerty
Webmaster / Président
Réactions :
Messages : 25088
Inscription : septembre 27, 2002, 9:41 pm

Surligner un mot dans un texte HTML

Message par Aurelienazerty »

Comme vous le savez, j'ai été confronté à un problème avec le moteur de recherche sur le site lorsque je voulais surligner les expressions trouvés... En effet, un str_replace posais quelques problème notament avec les histoire de casse, et surtout, celui-ci remplaceais le texte compris dans les balises HTML un

Code : Tout sélectionner

<a href='toto'>toto</a>
Devenait un

Code : Tout sélectionner

<a href='<span style='background-color:#ffff66'>toto</span>'>toto</a>
lorsque l'on voulais surligner toto...
Bref après avoir cherché une solution avec les expressions régulières dont voici des ducumentations interessantes:
Cours sur les expressions régulières
Syntaxe des masques (cours)
syntaxe des masques (nexen)
Documentation sur preg_replace
J'ai "dévellopé" une fonction spécifique que voici:

Code : Tout sélectionner

<?
/** Fonction surligner
@param $donne : chaine de caractère donnée, un texte pouvant contenir de l'HTML
@param $recherche: chaine de caractère, mot à souligner
@return une chaine de caractère au format HTML dont toutes les occurences (en ignorant la casse) de
$recherche contenus dans $donnee n'étant pas dans des balises HTML ont été surlignées*/
function surligner($donne, $recherche) {
	
	if (strlen($recherche) == 0) return $donne;
	
	$j = 0;
	$balise = false;
	$tmp = "";
	$sortie = "";
	for ($i = 0; $i < strlen($donne); $i++) {
		
		//Détection de balises HTML
		if (strcmp($donne[$i] ,"<")==0) {
			//Début d'une balise HTML
			$balise = true;
		} else {
			if ( ($balise) && (strcmp($donne[$i],">")==0) ) {
				//Fin d'une balise HTML
				$balise = false;
			}
		}
		
		if (!$balise) {
			//Nous ne sommes pas dans une balise
			if ($j == (strlen($recherche) - 1) ) {
				//Traitement du dernier élément de $recherche
				if  (strcmp(strtolower($recherche[$j]),strtolower($donne[$i]))==0) {
					//Recherche trouvé, on surligne
					$sortie .= "<span style='background-color:#ffff66'>" . $tmp . $donne[$i] . "</span>";
				} else {
					//Recherche non trouvé, on laisse tel quel
					$sortie .= $tmp . $donne[$i];
				}
				//RAZ de la "recherche"
				$j = 0;
				$tmp = "";
			} else {			
				//Comparaison ignorant la casse
				if (strcmp(strtolower($recherche[$j]),strtolower($donne[$i]))==0) {
					//construction de la chaine temporaire
					$tmp .= $donne[$i];
					//Avancer la recherche
					$j++;
				} else {
					//Recherche non trouvé, on laisse tel quel
					//On ajoute la chaine tmp qui peut être non vide
					//cas une partie était identique à $recherche
					$sortie .= $tmp . $donne[$i];
					//RAZ de la "recherche"
					$tmp = "";
					$j = 0;
				}
			}			
		} else {
			//Nous sommes dans une balise, nous ne fesons que recopier
			//Recopie
			$sortie .= $donne[$i];
		}
	}
	
	return $sortie;
}			
?>
Il existe sûrment une meilleure méthode pour arriver au même résultat, c'est pour celà que je vous invite à répondre à ce topic...
Dernière modification par Aurelienazerty le janvier 30, 2004, 11:30 am, modifié 1 fois.
Avatar de l’utilisateur
Nicolazerty
l'élu
Réactions :
Messages : 4114
Inscription : septembre 27, 2002, 2:59 pm

Message par Nicolazerty »

si t'as < dans le texte ca marche quand meme?
ex : RCL < OM
Résistance !
Avatar de l’utilisateur
Aurelienazerty
Webmaster / Président
Réactions :
Messages : 25088
Inscription : septembre 27, 2002, 9:41 pm

oui

Message par Aurelienazerty »

Vi ça marche, car le < est codée en HTML (je sais plus ce que ça donne) enfin c'est comme le & qui est & a m p ;
Avatar de l’utilisateur
Aurelienazerty
Webmaster / Président
Réactions :
Messages : 25088
Inscription : septembre 27, 2002, 9:41 pm

ça marche bien

Message par Aurelienazerty »

ça marche bien look ici
Par contre il y a des résultats assez surprennants... J'ai dût me gourer QQ part
Avatar de l’utilisateur
Aurelienazerty
Webmaster / Président
Réactions :
Messages : 25088
Inscription : septembre 27, 2002, 9:41 pm

correction de bug

Message par Aurelienazerty »

J'eusse fait une connerie dans mon prog, c'est rectifié now...
Il reste le "bug" identifié plus haut... A savoir que si une partie du mot est mis en forme (genre une lettre en gras) ben ça merdouille...
Avatar de l’utilisateur
Arken
Éleveur de srou
Réactions :
Messages : 5128
Inscription : septembre 27, 2002, 12:55 pm

Re: Surligner un mot dans un texte HTML

Message par Arken »

C'est corrigé ?
Avatar de l’utilisateur
Aurelienazerty
Webmaster / Président
Réactions :
Messages : 25088
Inscription : septembre 27, 2002, 9:41 pm

Que font les développeurs ?

Message par Aurelienazerty »

Je crains que le bug soit toujours présent, et que ce soit également le plus vieux code non retouché du site.
Avatar de l’utilisateur
Aurelienazerty
Webmaster / Président
Réactions :
Messages : 25088
Inscription : septembre 27, 2002, 9:41 pm

Remplacement de code moche

Message par Aurelienazerty »

16 ans plus tard, j'ai trouvé un code qui fait ça très bien à partir d'expressions régulières, j'ai adapté avec la balise MARK arrivé avec l'HTML5 :

Code : Tout sélectionner

function surligner($contenu, $recherche, $typeSurlignage = "exact", $exact = true, $typeRecherche = "FULLTEXT") {

	if (strlen($recherche) == 0) {
		return $contenu;
	}
	
	// Permet d'afficher les expressions entre guillemets en gras
	if(preg_match_all('/"(.*)"/i', $recherche, $args)) {
		foreach($args[0] as $arg) {
			$recherche = str_ireplace(array('"','\"'),array(' ',' '),$recherche);
		}
	}
	// Permet d'échapper les caractères du regex
	if(preg_match_all('([\+\*\?\/\'\"\-])', $recherche, $args)) {
		foreach($args[0] as $arg) {
			$recherche = str_ireplace(array('+', '*', '?', '/', "'", '"'),array('\+','\*','\?', '\/', '\'', ''),$recherche);
		}
	}

	$withaccent = array('à','á','â','ã','ä','ç','è','é','ê','ë','ì','í','î','ï','ñ','ò','ó','ô','õ','ö','ù','ú','û','ü','ý','ÿ','À','Á','Â','Ã','Ä','Ç','È','É','Ê','Ë','Ì','Í','Î','Ï','Ñ','Ò','Ó','Ô','Õ','Ö','Ù','Ú','Û','Ü','Ý');
	$withnoaccent = array('a','a','a','a','a','c','e','e','e','e','i','i','i','i','n','o','o','o','o','o','u','u','u','u','y','y','A','A','A','A','A','C','E','E','E','E','I','I','I','I','N','O','O','O','O','O','U','U','U','U','Y');
	if(preg_match('#[\p{Xan}][^a-zA-Z]#iu', $recherche)) {
		$recherche = str_ireplace($withaccent, $withnoaccent, htmlspecialchars(trim($recherche)));
	}

	// Adapte le surlignage des mots selon les besoins (chaîne exacte, mot complet ou sans)
	if($typeSurlignage == "exact" && (($exact == true && $typeRecherche != "LIKE") || ($exact == false && $typeRecherche == "FULLTEXT"))) {
		$contenu = preg_replace('/([[:blank:]<>\(\[\{\'\/].?:?;?,?)('.$recherche.')([\)\]\}.,;:!\?\/[:blank:]<>])/i', '$1<mark>$2</mark>$3', $contenu);
	} else if($typeSurlignage == "exact" && (($exact == true && $typeRecherche == "LIKE") || ($exact == false) && $typeRecherche != "FULLTEXT")) {
		$contenu = preg_replace('/('.$recherche.'{1,'.strlen($recherche).'})/i', '<mark>$1</mark>', $contenu);
	} else if($typeSurlignage == "total" || $typeSurlignage == "complet") {
		$contenu = preg_replace('/([[:blank:]<>])([^[:blank:]<>]*'.$recherche.'[^[:blank:]<>]*)([[:blank:]])/i', '$1<mark>$2</mark>$3', $contenu);
	}
	
	// Nettoyage des balises <hn> inféctées par la mise en gras
	if(preg_match_all('/<[\/]?[hH]+<mark>('.$recherche.')<\/mark>+/i', $contenu, $args)) {
		foreach($args[0] as $arg) {
			$contenu = preg_replace('/(<[\/]?[a-zA-Z]+)<mark>('.$recherche.')<\/mark(>)+/i', '$1$2$3', $contenu);
		}
	}

	// Nettoyage des autres balises inféctées par la mise en gras
	if(preg_match_all('/<[\/]?[^hH]?<mark>('.$recherche.')<\/mark>?(^>)*/i', $contenu, $args)) {
		foreach($args[0] as $arg) {
			$contenu = preg_replace('/(<[\/]?[^hH]?)<mark>('.$recherche.')<\/mark>?(^>)*/i', '$1$2$3$4', $contenu);
		}
	}
	
	// Nettoie les <mark> ajoutés en "trop" dans les attributs HTML courants (surtout src et href)
	// Ainsi, si un mot recherché est dans une URL, une class (...), les <mark> seront omis et tout fonctionnera...
	//preg_match_all('/(src|href|alt|title|class|id|rel)=["\']{1}[^\'"]+('.$recherche.')[^\'"]+["\']{1}/i',$contenu, $args)
	if(preg_match_all('/(src|href|alt|title|class|id|rel)=["\']{1}[^\'"]+('.$recherche.')[^\'"]+["\']{1}/i',$contenu, $args)) {
		foreach($args[0] as $arg) {
			$contenu = preg_replace('/(src|href|alt|title|class|id|rel)*(=["\']{1}[^\'"]*)<mark>+('.$recherche.')<\/mark>+([^\'"]*["\']{1})/i', '$1$2$3$4', $contenu);
		}
	}
	
	return $contenu;
}
Dernière modification par Aurelienazerty le mars 28, 2021, 1:02 am, modifié 1 fois.
Raison : Modif reprise