Oui, la recherche (.*) finale du motif empêche qu'il soit traité plusieurs fois. Pour éviter la boucle (et la gourmandise de l'opérateur *), une variante "améliorée" pour les cas toujours assez simples serait du genre :
1 2 3
| $str = "<strong><strong>mot1</strong>mot2</strong>blabla<b><b>ddddd</b>aaa</b>";
$out = preg_replace("/(<[^>]+>)(.*?)(\\1)(.*?)(<\/[^>]+>)(.*?)(\\5)/", "$1$2$4$6$7$8", $str);
echo str_replace(array("<", ">"), array("[", "]"), print_r($out, true)); |
Les (\\1) et (\\5) sont les références arrière dont je parlais plus haut :
\1 récupère le texte satisfaisant la première parenthèse capturante (anti-slash doublé puisque c'est un caractère de contrôle : il faut de dé-spécialiser) : il récupère donc la première occurrence du mot capturé par la première paire de parenthèses.
Idem pour \5 en transposant.
Note que ça ne marche toujours que dans les cas simples de chaînes évoqués plus haut : une chaîne correcte comme
<strong>mot1</strong>aaaaaaaaaa<strong>mot2</strong>
ne sera pas correctement traitée, elle. Il faut retravailler l'expression régulière pour garantir qu'il n'y a pas de balise fermante du type capturé entre deux balises ouvrantes de ce même type. Et ce n'est que le début des ennuis à prévoir, sauf bien sûr si le code HTML à nettoyer est limité, d'un format stable, simple et bien cerné.
Partager