PHWinfo banniere

Titres
PORTAIL ANNUAIRE ARTICLES COMPARATEUR HÉBERGEURS DEVIS FORUMS RÉDUCTEUR D'URL
Précédent   PHWinfo > Autres forums > Forum Programmation & Conception > fr.comp.lang.php > Circonscrire un eregi_replace ?
S'inscrire FAQ Membres Recherche Messages du jour Marquer les forums comme lus
Circonscrire un eregi_replace ?

Réponse
 
LinkBack Outils de la discussion
Vieux 01/10/2007, 09h20   #1
paul
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Circonscrire un eregi_replace ?

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
  Réponse avec citation
Vieux 01/10/2007, 11h49   #2
Mickael Wolff
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Circonscrire un eregi_replace ?

paul a écrit :

> 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
  Réponse avec citation
Vieux 01/10/2007, 11h49   #3
Mickael Wolff
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Circonscrire un eregi_replace ?

paul a écrit :

> 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
  Réponse avec citation
Vieux 01/10/2007, 12h17   #4
Olivier Miakinen
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Circonscrire un eregi_replace ?

Le 01/10/2007 10:20, paul a écrit :
>
> 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 ?...


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|>)$quoi\b/",
"<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);
  Réponse avec citation
Vieux 01/10/2007, 12h17   #5
Olivier Miakinen
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Circonscrire un eregi_replace ?

Le 01/10/2007 10:20, paul a écrit :
>
> 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 ?...


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|>)$quoi\b/",
"<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);
  Réponse avec citation
Vieux 01/10/2007, 14h01   #6
Olivier Miakinen
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Circonscrire un eregi_replace ?

Le 01/10/2007 13:17, Olivier Miakinen a écrit :
> (?<=\s|>)


Ok à priori.

> $contenu = preg_replace("/?<=\s|>)$quoi\b/",

^^
Il manque une parenthèse ici. Il y a peut-être d'autres erreurs car je
n'ai rien testé.
  Réponse avec citation
Vieux 01/10/2007, 14h01   #7
Mickael Wolff
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Circonscrire un eregi_replace ?

Bonjour,

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

Mickael Wolff a écrit :

> $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
  Réponse avec citation
Vieux 01/10/2007, 14h01   #8
Olivier Miakinen
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Circonscrire un eregi_replace ?

Le 01/10/2007 13:17, Olivier Miakinen a écrit :
> (?<=\s|>)


Ok à priori.

> $contenu = preg_replace("/?<=\s|>)$quoi\b/",

^^
Il manque une parenthèse ici. Il y a peut-être d'autres erreurs car je
n'ai rien testé.
  Réponse avec citation
Vieux 01/10/2007, 14h01   #9
Mickael Wolff
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Circonscrire un eregi_replace ?

Bonjour,

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

Mickael Wolff a écrit :

> $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
  Réponse avec citation
Vieux 02/10/2007, 08h35   #10
paul
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Circonscrire un eregi_replace ?

In article <4700d4e4$1@neottia.net>,
Olivier Miakinen <om+news@miakinen.net> wrote:

> Le 01/10/2007 10:20, paul a écrit :
> >
> > 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 ?...

>
> 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.
  Réponse avec citation
Vieux 02/10/2007, 11h15   #11
Olivier Miakinen
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Circonscrire un eregi_replace ?

Le 02/10/2007 09:35, paul a écrit :
>
> 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.
  Réponse avec citation
Vieux 02/10/2007, 11h15   #12
Olivier Miakinen
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Circonscrire un eregi_replace ?

Le 02/10/2007 09:35, paul a écrit :
>
> 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.
  Réponse avec citation
Vieux 02/10/2007, 17h49   #13
paul
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Circonscrire un eregi_replace ?

In article <4701f78b$1@neottia.net>,
Olivier Miakinen <om+news@miakinen.net> 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 ?...
  Réponse avec citation
Vieux 02/10/2007, 18h06   #14
Olivier Miakinen
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Circonscrire un eregi_replace ?

Le 02/10/2007 18:49, paul a écrit :
>
>> >> 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", ...
  Réponse avec citation
Vieux 02/10/2007, 18h06   #15
Olivier Miakinen
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Circonscrire un eregi_replace ?

Le 02/10/2007 18:49, paul a écrit :
>
>> >> 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", ...
  Réponse avec citation
Réponse


Outils de la discussion

Règles de messages
Vous ne pouvez pas créer de nouvelles discussions
Vous ne pouvez pas envoyer des réponses
Vous ne pouvez pas envoyer des pièces jointes
Vous ne pouvez pas modifier vos messages

Les balises BB sont activées : oui
Les smileys sont activés : oui
La balise [IMG] est activée : oui
Le code HTML peut être employé : non
Trackbacks are oui
Pingbacks are oui
Refbacks are oui


Fuseau horaire GMT +1. Il est actuellement 13h20.


Édité par : vBulletin® version 3.7.3
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.2.0 RC5 Tous droits réservés.
Version française #16 par l'association vBulletin francophone
PHWinfo est un site Éducation Sans Frontières ©2000-2008
Ad Management by RedTyger
©Tous droits réservés par les parties respectives
Page generated in 0,23768 seconds with 23 queries