preg_replace recursif

Eléphanteau du PHP | 38 Messages

22 août 2011, 15:18

Bonjour,

J'aimerai faire un preg_replace recursif pour transformer du bbcode en html.

Exemple

Code : Tout sélectionner

[quote]première quote[quote]seconde quote[/quote][/quote]
donne
première quote
seconde quote
Actuellement j'ai un

Code : Tout sélectionner

$out = preg_replace('#\[quote\](.*)\[/quote\]#Uis','<div class="quote">$1</div>');
Mais ça ne le fait pas recursivement.

J'ai pas mal parcouru le web, j'ai vu un flag "e" mais qui bouffe des ressources, un (?R) qui donne une recursivité, ou un preg_replace_recursif mais je n'ai pas réussit à avoir ce que je voulais.
J'en ai vu qui propose un preg_replace_recursif avec un str_replace mais c'est mal car si dans le bbcode il y a trop de balises fermantes, ça ferme des div que ça devrait pas.

Merci si quelqu'un a la solution, ici sur le forum ça fonctionne bien, j'aimerai bien la même chose !

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

22 août 2011, 20:25

salut,

j'ai rechercher,rapidement, dans le code phpbb3 mais c'est assez obscure leur truc et les commentaires sont pas super claire :/

a tu essayer avec un preg_match_callback ? (le plus simple étant de remplacer chaque quote et </quote individuellement si le masque "match" ?)

@+
Il en faut peu pour être heureux ......

Eléphanteau du PHP | 38 Messages

22 août 2011, 20:52

J'ai regardé aussi dans phpbb et j'ai pas pigé.

preg_replace_callback j'ai essayé mais ça fait pas ce que je veux visiblement :/

Remplacer individuellement ça pose des soucis quand y'a trop de balises ouvrantes ou fermantes, ça ouvre / ferme des balises htmp ou ça devrait pas.

Y'a bien la solution du while preg_match avec un preg_replace dedans mais niveau perf c'est pas bon du tout.

Le preg_replace_callback est je pense la solution mais j'ai pas réussit à me dépatouiller !

Je me suis aidé de ça http://www.expreg.com/expreg_article.php?art=citations mais son truc est mal car il str_replace et donc trop de balises fermantes = trop de balises html.

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

22 août 2011, 22:48

il faut compter les balise ouvrant et fermante et fermer autant de balise fermant que de balise ouverte, par contre ça fonctionne aussi dans l'autre sens (si trop d'ouvrante ;) ).

@+
Il en faut peu pour être heureux ......

Eléphanteau du PHP | 38 Messages

23 août 2011, 10:02

C'est pas la question du problème ça, c'est un détournement, et j'aime pas trop car tu sais pas ou doivent d'ouvrir ou se fermer les balises manquantes ou en trop !
La le soucis c'est remplacer des balises imbriquées avec un preg_replace proprement, je suis sur que c'est possible, d'adapter le code que j'ai filé un peu plus haut.

devlop78
Invité n'ayant pas de compte PHPfrance

24 août 2011, 20:32

Tu as les masques récursifs http://www.php.net/manual/fr/regexp.ref ... ursive.php

qui sont justement fait pour ce qui est imbriqué. Mais perso, j'ai essayé, et même leur exemple ne fonctionnait pas. Il te manque plus qu'à développer un bon algo ;)

Petit nouveau ! | 6 Messages

04 sept. 2011, 17:35

Bonjour, pour ma part pour faire mon propre bbcode je passe par un fichier de configuration (en xml, même si le json aurait été plus léger à ce propos, mais bon...)
Par exemple, voici la config d'un bbcode de base (avec pas trop de fonctionalités

Code : Tout sélectionner

<?xml version="1.0" encoding="UTF-8"?> <!-- Document : bbCode_config.xml Created on : 28 juillet 2011, 20:30 Author : isen Description: Ce document offre une configuration du BBcode du site dans le but d'une intégration simple des balises ->soit elles sont remplacées par <span class="replace_class">...</span> ->soit elles sont remplacées par <replace_tag>...</replace_tag> ->soit elles seront à nouveau parsée par recursive_parser Si un tag accepte une variable alors sa configuration donne le nom de cette variable --> <allTags> <tag name="u" replace_tag="<span class="souligne">$1</span>"/> <tag name="b" replace_tag="<span class="gras">$1</span>"/> <tag name="i" replace_tag="<span class="italique">$1</span>"/> <tag name="color" replace_tag="<span style="color:$1;">$2</span>" req_vars="color"/> <tag name="ul" replace_tag="<ul>$1</ul>"/> <tag name="ol" replace_tag="<ol>$1</ol>"/> <tag name="li" replace_tag="<li>$1</li>" sub_tag_of="ul,ol"/> <tag name="quote" replace_tag="<blockquote><p>Ecrit par : $1 </p><p>$2</p>" without_vars="<blockquote><p>$1</p>" recursive_limit="5" req_vars="auteur"/> <tag name="iquote" replace_tag="<q>$1</q>"/> <tag name="code" recursive_parser="CodeParser" req_vars="langage"/> <tag name="url" replace_tag="<a href="$2"> $1</a>" without_vars="<a href="$1"> $1</a>" vars="link"/> <tag name="img" replace_tag="<img src="$1"/>"/> </allTags>
comme tu le vois, pour le li (le * sur ce forum) j'ai précisé "sub_tag_of". Lorsque mon parser découvre cet attribut il dit "ne transforme que les \[li].+\[/li] qui sont à l'intérieur de <ul> ou <ol> (qui ont déjà été parsés).

Voici le bout de code qui correspond dans mon parser :
 if($tag->hasAttribute('sub_tag_of')){
                
                    //on cherche les éléments déjà parsés
                    $tags=explode(',', $tag->getAttribute('sub_tag_of'));

                    foreach($tags as $cur){
                        $matches=array();
                        $change=array();
                        // on sélection ces éléments déjà parsés
                        preg_match_all('#<'.$cur.'>(.+)</'.$cur.'>#UimS', $this->texteToParse, $matches);
                        //puis on parse les éléments intérieurs du type $tag->getAttribute('name')
                       
                        $change=$this->subTagParse($matches, $tag->getAttribute('name'),$regex);
                        //Ensuite remplace les anciens textes par les nouveaux
                        foreach($matches[1] as $key=>$value){
                            $newText=str_replace($value, $change[$key], $matches[0][$key]);
                            $this->texteToParse=str_replace($matches[0][$key], $newText, $this->texteToParse);
                        }
                    }
                }

ViPHP
ViPHP | 5462 Messages

10 sept. 2011, 18:30

pas besoin de récursif fait juste
preg_replace('/\[(\/?)quote\]/', '<$1blockquote>', $text);

Eléphant du PHP | 121 Messages

13 sept. 2011, 17:39

Le récursif avec preg_replace() il vaut mieux oublier. Par contre tu peux construire un arbre de tags puis traiter cet arbre. Sur mon blog j'explique comment faire avec du HTML, mais le principe reste le même: http://weirdog.com/blog/php/un-parser-h ... leger.html