Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Circonscrire un eregi_replace ?

8 réponses
Avatar
paul
Bonjour,

j'ai un module de recherche sur un site. Et sur la page de résultats, je
surligne le résultat. OK ça marche.

$Contenu = eregi_replace($quoi, "<span class=\"highlight\">\\0</span>",
$Contenu);

Oui mais, le seul souci c'est que ça me casse le code à l'intérieur des
liens interactifs puisque ça ajoute le span class. Du style :
<a href="http://www.<span class="highlight">trucmuche</span>.com">mon
lien</a>

Comment dire $Contenu = eregi_replace sauf là où c'est encadré par <a
href et le > suivant ?...

C'est possible ça ?
Merci pour l'aide

8 réponses

Avatar
Mickael Wolff

C'est possible ça ?
Merci pour l'aide


Attention, la solution que je vais te proposer est très bourrin, ça
peut éventuellement consommer beaucoup de mémoire. L'astuce consisterait
à utiliser un parser de HTML/XML : DOMDocument
<http://fr2.php.net/manual/fr/ref.dom.php> avec DOMXpath
<http://fr2.php.net/manual/fr/function.dom-domxpath-construct.php>, puis
en traitant les résultant de la requête avec preg_match.

Par exemple, pas testé et fait de tête (j'vais pas tout faire non plus
:p) :

<?php

$word = 'toto' ;

$doc = DOMDocument::loadHTML($output) ;
$doc->validate() ;
$finder = new DOMXPath('//text()') ;

foreach($finder as $textNode)
{
// L'expression régulière ci-dessous ne détectera que la première
occurrence du mot $word.
if(preg_match('`^(.*)b('.$word.')b(.*)$`', $textNode.value, $matches))
{
$hlSpan = $doc->createElement('span', $word) ;
$hlSpan->setAttribute('class', 'highlight') ;

$beforeNode = $textNode.ownderDocument.createTextNode($matches[1]) ;
$afterNode = $textNode.ownderDocument.createTextNode($matches[3]) ;

$textNode.parentNode.appendChild($beforeText) ;
$textNode.parentNode.appendChild($hlSpan) ;
$textNode.parentNode.appendChild($afterText) ;

$textNode.parentNode.removeChild($textNode) ;
}
}

echo $doc->saveHTML() ;

?>

Les remarques sur ma façon de coder sont les bienvenues, ou sur des
erreurs aussi.

Bon début de semaine à tous !
--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org

Avatar
Olivier Miakinen

j'ai un module de recherche sur un site. Et sur la page de résultats, je
surligne le résultat. OK ça marche.

$Contenu = eregi_replace($quoi, "<span class="highlight"></span>",
$Contenu);

Oui mais, le seul souci c'est que ça me casse le code à l'intérieur des
liens interactifs puisque ça ajoute le span class. Du style :
<a href="http://www.<span class="highlight">trucmuche</span>.com">mon
lien</a>

Comment dire $Contenu = eregi_replace sauf là où c'est encadré par <a
href et le > suivant ?...


Le plus simple (et le plus sûr) me semble être d'utiliser un analyseur
syntaxique de HTML qui te construit un arbre, et tu n'as plus qu'à faire
le remplacement dans les feuilles avant de générer le résultat. Avec des
expressions rationnelles tu ne peux faire que du bricolage.


Essayons tout de même de bricoler. Je suppose que $quoi contient un
mot, avec donc des lettres le plus souvent, mais pas de signes de
ponctuation et surtout pas d'espaces. Pour éviter le problème que tu
signales, tu peux vérifier avec une « assertion arrière » que le mot
est précédé d'un espace ou du caractère « > » et rien d'autre :
(?<=s|>)
Par la même occasion tu peux aussi vérifier qu'il se termine à une
frontière de mot :
b
Cela donnera donc :
$contenu = preg_replace("/?<=s|>)$quoib/",
"<span class='highlight'>$0</span>", $contenu);


Note que l'on ne peut pas à ma connaissance utiliser d'assertion arrière
allant chercher le « a href » car elle ne serait pas de longueur fixe.


Une autre méthode consisterait à rechercher toutes les chaînes comprises
entre « > » et « < » et à effectuer le remplacement que tu souhaites
dans chacune de ces chaînes. Par exemple :
function ma_fonction($matches) {
return preg_replace("/$quoi/", "<span class='highlight'>$0</span>",
$matches[0]);
}
$contenu = preg_replace_callback("/>.*</sU", "ma_fonction", $contenu);

Avatar
Olivier Miakinen
(?<=s|>)


Ok à priori.

$contenu = preg_replace("/?<=s|>)$quoib/",
^^

Il manque une parenthèse ici. Il y a peut-être d'autres erreurs car je
n'ai rien testé.

Avatar
Mickael Wolff
Bonjour,

Petite correction rapide, car j'ai bien évidemment oublié une étape
cruciale en allant trop vite, qui est l'évaluation du XPath.


$doc = DOMDocument::loadHTML($output) ;
$doc->validate() ;

- $finder = new DOMXPath('//text()') ;
+ $finder = new DOMXPath($doc) ;


- foreach($nodes as $textNode)
+ foreach($finder->evaluate('//text()') as $textNode)


{


--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org

Avatar
paul
In article <4700d4e4$,
Olivier Miakinen <om+ wrote:


j'ai un module de recherche sur un site. Et sur la page de résultats, je
surligne le résultat. OK ça marche.

$Contenu = eregi_replace($quoi, "<span class="highlight"></span>",
$Contenu);

Oui mais, le seul souci c'est que ça me casse le code à l'intérieur des
liens interactifs puisque ça ajoute le span class. Du style :
<a href="http://www.<span class="highlight">trucmuche</span>.com">mon
lien</a>

Comment dire $Contenu = eregi_replace sauf là où c'est encadré par <a
href et le > suivant ?...


Essayons tout de même de bricoler. Je suppose que $quoi contient un
mot, avec donc des lettres le plus souvent, mais pas de signes de
ponctuation et surtout pas d'espaces. Pour éviter le problème que tu
signales, tu peux vérifier avec une « assertion arrière » que le mot
est précédé d'un espace ou du caractère « > » et rien d'autre


Ben je n'interdis pas de faire des recherches sur plusieurs mots et
éventuellement avec de la ponctuation... ça semble bien fonctionner
d'ailleurs...


Une autre méthode consisterait à rechercher toutes les chaînes comprises
entre « > » et « < » et à effectuer le remplacement que tu souhaites
dans chacune de ces chaînes. Par exemple :
function ma_fonction($matches) {
return preg_replace("/$quoi/", "<span class='highlight'>$0</span>",
$matches[0]);
}
$contenu = preg_replace_callback("/>.*</sU", "ma_fonction", $contenu);


Pas mal vu, sauf qu'il n'y a malheureusement pas forcément de lien dans
le contenu !...
;-)



C'est pour ça que je disais que s'il y a un ou des liens il faudrait ne
pas intervenir avec le eregi_replace entre les <a href et le > suivant.


Avatar
Olivier Miakinen

Ben je n'interdis pas de faire des recherches sur plusieurs mots et
éventuellement avec de la ponctuation... ça semble bien fonctionner
d'ailleurs...


Donc, tu autorises aussi les recherches sur « link rel="stylesheet" »,
sur « meta http-equiv » et ainsi de suite ? Dans ce cas je ne vois pas
pourquoi le contenu des attributs href serait le seul à protéger.

Une autre méthode consisterait à rechercher toutes les chaînes comprises
entre « > » et « < » et à effectuer le remplacement que tu souhaites
dans chacune de ces chaînes. Par exemple :
function ma_fonction($matches) {
return preg_replace("/$quoi/", "<span class='highlight'>$0</span>",
$matches[0]);
}
$contenu = preg_replace_callback("/>.*</sU", "ma_fonction", $contenu);


Pas mal vu, sauf qu'il n'y a malheureusement pas forcément de lien dans
le contenu !...


Je ne comprends pas ta remarque. Il n'y aura *jamais* de lien dans le
contenu, en tout cas jamais de balises <a> ou </a>, et justement il me
semble que c'est ce que tu cherches : modifier le contenu pour mettre
certains mots en évidence, mais ne surtout pas toucher aux balises HTML,
dont les liens.

C'est pour ça que je disais que s'il y a un ou des liens il faudrait ne
pas intervenir avec le eregi_replace entre les <a href et le > suivant.


Si tu ne prends que ce qui se trouve entre un > fermant et le < ouvrant
qui suit, ça ne changera pas ce qui se trouve entre un < ouvrant et le >
fermant correspondant. Bien sûr, il faudrait peut-être affiner si jamais
tu t'autorisais à mettre dans le contenu des « > » non encodés en
« &gt; », mais j'ai supposé que ce n'était pas le cas.


Avatar
paul
In article <4701f78b$,
Olivier Miakinen <om+ wrote:

Une autre méthode consisterait à rechercher toutes les chaînes comprises
entre « > » et « < » et à effectuer le remplacement que tu souhaites
dans chacune de ces chaînes. Par exemple :
function ma_fonction($matches) {
return preg_replace("/$quoi/", "<span class='highlight'>$0</span>",
$matches[0]);
}
$contenu = preg_replace_callback("/>.*</sU", "ma_fonction", $contenu);


Pas mal vu, sauf qu'il n'y a malheureusement pas forcément de lien dans
le contenu !...


Je ne comprends pas ta remarque.


cf plus bas

C'est pour ça que je disais que s'il y a un ou des liens il faudrait ne
pas intervenir avec le eregi_replace entre les <a href et le > suivant.


Si tu ne prends que ce qui se trouve entre un > fermant et le < ouvrant
qui suit, ça ne changera pas ce qui se trouve entre un < ouvrant et le >
fermant correspondant.


Mais euh... s'il n'y a pas de lien dans le contenu, le preg_replace ne
retournera rien, non ?...



Avatar
Olivier Miakinen

function ma_fonction($matches) {
return preg_replace("/$quoi/", "<span class='highlight'>$0</span>",
$matches[0]);
}
$contenu = preg_replace_callback("/>.*</sU", "ma_fonction", $contenu);




Mais euh... s'il n'y a pas de lien dans le contenu, le preg_replace ne
retournera rien, non ?...


Ben si, il retournera la chaîne inchangée, exactement comme avec
eregi_replace (que tu peux d'ailleurs garder, même si c'est en général
plus lent).

Au fait, comme tu fais une recherche insensible à la casse,
il faut aussi rajouter un « i » si tu choisis preg au lieu de ereg :
preg_replace("/$quoi/i", ...

Par ailleurs, si tu peux avoir des « / » dans les mots cherchés, il vaut
mieux utiliser un autre caractère de séparation. Je suggère « < » qui ne
peut pas s'y trouver (il doit être remplacé par &lt;), donc :
preg_replace("<$quoi<i", ...