OVH Cloud OVH Cloud

preg_replace

3 réponses
Avatar
Stephane Santon
Bonjour,

Pour faire un filtre sous spip, je voudrais remplacer toutes les
occurences de

<p class="spip">§1 blablabla</p>
par
<h1>blablabla></h1>

j'ai alors écris :

$newtexte = preg_replace( "/<p class=\"spip\">§([1-9]{1}) (.*)<\/p>/",
"<h$1>$2<h$1>", $texte);

Mais seule la première occurence est remplacée.
Comment corriger ?
Merci

--
** Anti-Spam : ajouter [usenet] dans l'objet pour ne pas être rejeté.
--
Cordialement, Stéphane *** http://www.team-santonum.com
Loisirs, nature, arts, technologie : accueil en Charente-Maritime

BTS Electrotechnique *** http://enselec.team-santonum.com

3 réponses

Avatar
Olivier Miakinen
[ je mets ma réponse dans fr.comp.lang.php sans respecter le suivi car
il semble que le forum en alt n'existe pas chez moi ]


[remplacement de]
<p class="spip">§1 blablabla</p>
par
<h1>blablabla></h1>


Ok.

$newtexte = preg_replace( "/<p class="spip">§([1-9]{1}) (.*)</p>/",
"<h$1>$2<h$1>", $texte);

Mais seule la première occurence est remplacée.


Tu es sûr que c'est ça le symptome ? Il ne remplacerait pas plutôt tout
ce qui est entre le premier <p> et le dernier </p> sans s'arrêter aux
frontières de paragraphes ?

Si blablabla ne peut pas contenir de balises, alors le plus simple
consiste à remplacer (.*) par ([^<]*).

J'en profite pour te signaler deux autres choses. La première, c'est
qu'une « répétition une fois et une seule » n'est pas très utile, et tu
peux donc remplacer [1-9]{1} par [1-9]. Par ailleurs, comme il n'existe
pas d'éléments de titres de 7e niveau ou plus, je conseillerais plutôt
[1-6].

Donc :
$newtexte = preg_replace( "/<p class="spip">§([1-6]) ([^<]*)</p>/",
"<h$1>$2<h$1>", $texte);

Maintenant, pour éviter d'échapper les doubles guillemets tu peux en
remplacer deux par des simples et il vaut peut-être mieux faire pareil
pour la chaîne de remplacement puisque tu mets des $ au lieu de $ :
$newtexte = preg_replace( '/<p class="spip">§([1-6]) ([^<]*)</p>/',
'<h$1>$2<h$1>', $texte);

Et enfin, pour éviter d'échapper les / tu peux utiliser un autre
caractère parmi ceux que tu n'utilises pas, par exemple :
$newtexte = preg_replace( '|<p class="spip">§([1-6]) ([^<]*)</p>|',
'<h$1>$2<h$1>', $texte);

Avatar
Stephane Santon
Bonjour,

Olivier Miakinen a formulé ce mardi :
Tu es sûr que c'est ça le symptome ? Il ne remplacerait pas plutôt tout
ce qui est entre le premier <p> et le dernier </p> sans s'arrêter aux
frontières de paragraphes ?

Donc :
$newtexte = preg_replace( '|<p class="spip">§([1-6]) ([^<]*)</p>|',
'<h$1>$2<h$1>', $texte);


Merci de tous ces conseils, c'est suivi et corrigé.

En fait le problème est ailleurs :
C'est que ça ne détecte pas l'expression lorsqu'il y a un saut de ligne
entre le <p class="spip"> et le </p>

Le caractère de saut de ligne n'est-il pas pris en compte dans
l'expression régulière (.*) ??

--
** Anti-Spam : ajouter [usenet] dans l'objet pour ne pas être rejeté.
--
Cordialement, Stéphane *** http://www.team-santonum.com
Loisirs, nature, arts, technologie : accueil en Charente-Maritime

BTS Electrotechnique *** http://enselec.team-santonum.com

Avatar
Olivier Miakinen

$newtexte = preg_replace( '|<p class="spip">§([1-6]) ([^<]*)</p>|',
'<h$1>$2<h$1>', $texte);


En fait le problème est ailleurs :
C'est que ça ne détecte pas l'expression lorsqu'il y a un saut de ligne
entre le <p class="spip"> et le </p>

Le caractère de saut de ligne n'est-il pas pris en compte dans
l'expression régulière (.*) ??


En effet, sauf si on le spécifie explicitement :

<cit. http://fr.php.net/manual/en/reference.pcre.pattern.modifiers.php>
s (PCRE_DOTALL)
Avec cette option, le méta caractère point (.) remplace n'importe
quel caractère, y compris les nouvelles lignes. Sans cette option, le
caractère point ne remplace pas les nouvelles lignes. Cette option est
équivalente à l'option Perl /s. Une classe de caractères négative telle
que [^a] acceptera toujours les caractères de nouvelles lignes,
indépendamment de cette option.
</cit.>

Note que si tu gardes l'idée du [^<] tu n'as pas besoin de l'option s.
Mais si tes paragraphes peuvent contenir d'autres balises, il faut
remettre le « . », ajouter l'option s, mais pour ne pas tomber sur
l'autre problème que je soulevais il faut en plus rajouter l'option U :

<cit. http://fr.php.net/manual/en/reference.pcre.pattern.modifiers.php>
U (PCRE_UNGREEDY)
Cette option inverse la tendance à la gourmandise des expressions
rationnelles. Vous pouvez aussi inverser cette tendance au coup par coup
avec un ?. De même, si cette option est activée, le ? rendra gourmand
une séquence. Cette option n'est pas compatible avec Perl. Elle peut
aussi être mise dans le masque avec l'option ?U dans le pattern ou par
un point d'interrogation avant le quantifieur (.e.g. .*?).
</cit.>

Ce qui donne :
$newtexte = preg_replace( '|<p class="spip">§([1-6]) (.*)</p>|sU',
'<h$1>$2</h$1>', $texte);
^
^
(un petit oubli que je n'avais pas vu)