Expressions régulières pour coloration syntaxique
RésoluMihawk Messages postés 4753 Statut Contributeur -
Je rencontre un souci gênant depuis quelques temps. Je souhaite faire de la coloration syntaxique sans passer par les traditionnels highlight_string et autres. Je suis donc en train de créer une fonction toute faite. Je vous passe les détails, voici l'important :
Je colorie les quotes entre " " ou ' ' en bleu :
$tab = preg_replace('#"(.*)"#msU','<span style="color:blue">$0</span>', $tab);
$tab = preg_replace('#\'(.*)\'#msU','<span style="color:blue">$0</span>', $tab);
Puis les commentaires en gris :
$tab['exemple'] = preg_replace('#\/\*(.*)\*\/#msU','<span style="color:grey"><br/>$0<br/></span>', $tab['exemple']);
Mon souci étant que les quotes qui se trouvent dans les commentaires apparaissent en bleu et non pas en gris.
J'ai essayé de faire quelque chose comme ça :
$tab = preg_replace('#\/\*(?!.*\*\/)span#', '\/\*$1\*\/', $tab);
(grossomodo, si on a un /* suivi d'un span avant un */, alors on a une quote dans un commentaire)
Mais ça ne fonctionne pas du tout. Ma piste est peut-être bonne et je me suis planté, ou alors mon idée est pourrie. Mais je ne vois pas comment faire.
Des idées ? Merci d'avance !
Mickaël.
PS : $tab est ici un string correspondant à une ligne d'une requête SQL. Ma fonction est appelée dans un while et sera donc effectuée pour chaque ligne de ma table SQL.
L'appel est celui-ci :
$tab[$ligne['id']] = replaceArray($tab[$ligne['id']]);
6 réponses
Le sujet porte sur la coloration syntaxique en PHP via des expressions régulières, colorant les guillemets en bleu et les commentaires en gris, tout en évitant que les quotes dans les commentaires restent bleu. Plusieurs répondants proposent d'abord colorer les guillemets puis les commentaires, puis de corriger les cas indésirables par étapes séparées afin d'éviter qu'une transformation n'écrase l'autre. Ils soulignent aussi que le comportement des motifs (.*) peut capturer du texte traversant des délimiteurs, risquant d'englober des parties non prévues, obligeant à restreindre les caractères ou à utiliser des classes négatives. D'autres suggèrent des solutions en plusieurs passes ou l'utilisation de patrons non capturant, mais les essais montrent que les cas complexes restent difficiles à maîtriser.
-
Hello,
Tu cherches à faire quelque chose de vraiment pas simple, et tu te heurtes à un problème connu et chiant : appliquer deux replace à un texte, sachant que chaque replace peut influer sur l'autre !
Dans ton cas je ferai ceci :
1/ Coloration des guillemets en bleu
2/ Coloration des commentaires en gris
3/ Remplacement des bleus indésirables par du gris
En gros pour 1/ et 2/ rien ne change.
Pour le 3/ je pensais à un truc du genre
$tab = preg_replace("#\/\*(.*)color\:blue(.*)\/\*#", "/*$1color:grey$2*/", $tab);
Sachant que tu dois faire très attention à tes (.*).
En effet, si tu cherches par exemple "//.*//" et que ton texte est le suivant : "// bonjour // à tous //" alors le (.*) peut aussi bien contenir "bonjour" que "bonjour // à tous" tu vois ce que je veux dire ?
-
D'abord, merci de ta réponse. :)
J'étais arrivé à quelque chose comme ça, oui.$tab = preg_replace('#\/\*(.*)<span style="color:blue">(.*)</span>(.*)\*\/#msU', '/*$1$2$3/*', $tab);
Le souci étant que dans le cas où on trouve quelque chose comme ça :/* blablabla */ [code] /* blablabla */ [code]
Eh bien... le regex considère le premier /* et le dernier */. Donc le premier bout de code subit aussi la suppression du color:blue et c'est pas chouette.
J'ai pas encore trouvé comment faire. Au début, j'avais pensé exclure les caractères */ de $1, $2 et $3, mais j'ai pas réussi à faire quelque chose de fonctionnel. -
-
-
À ce moment-là il faut supprimer l'utilisation du (.*) qui est beaucoup trop général. En fait la meilleure solution serait de ne pas utiliser de slash '/' dans tes commentaires afin d'être sûr qu'un slash marche la fin d'un commentaire. Tu remplaces ensuite (.*) par ([^/]*). De même il faut remplacer .* par [^<]* si tu veux ensuite détecter un "<span". etc. Exemple !
$tab = preg_replace('#\/\*([^<]*)<span style="color:blue">([^<]*)</span>([^*\]*)/#msU', '/*$1$2$3/*', $tab);
À tester car je ne suis pas sûr du dernier crochet !-
Pas mieux.
Tu as oublié (par contre) de fermer le commentaire dans le pattern, ça m'a fait un petit bug. Et dans ton dernier [ ], tu mets un antislash sans / derrière, ce qui fait qu'il échappe le crochet de fermeture et que ça pète tout. :p
Ca donne ça :$tab = preg_replace('#\/\*([^<]*)<span style="color:blue">([^<]*)</span>([^*\/]*)\/\*#msU', '/*$1$2$3/*', $tab);
Cela dit, ça ne marche pas mieux mais je ne comprends pas pourquoi, ça semble juste. Ca ne produit aucun résultat visible sur la page. -
Au temps pour moi ce n'est pas un antislash mais un slash que je voulais mettre dans la dernier crocher. Il ne faut pas échapper dans les classes.:
$tab = preg_replace('#\/\*([^<]*)<span style="color:blue">([^<]*)</span>([^*/]*)\/\*#msU', '/*$1$2$3/*', $tab);
Cela dit, avec ce code ton commentaire ne doit contenir ni '*' ni '/' -
En effet, au temps pour moi !
Malheureusement, ça ne fonctionne toujours pas. J'ai pensé que ça venait du fait qu'un */ pouvait se cacher dans les deux premières classes.
Du coup j'ai tenté :
$tab = preg_replace('#\/\*([^*/]*)<span style="color:blue">([^*/]*)</span>([^*/]*)\/\*#msU', '/*$1$2$3/*', $tab);
Mais c'est pas mieux.
Je commence à désespérer, les regex sont vraiment moins évidents que je pensais. -
-
function getCLASSFormulaire($tab_param) {
/* Récupère tous les attributs de la classe dans un array */
$tab_attribut_detailles=getCLASSTableAttributDetailles();
if(!$tab_param['class_id']) {
$tab_param['class_id']=$tab_param['id'];
}
$data=getCLASSData($tab_param);
$tab_attribut_valeur=initAttributData($tab_attribut_detailles, $data);
$tab_fieldset['0']['legend']='LEGEND 0';
$tab_fieldset['0']['column']=0;
$tab_param_form['fieldset']=$tab_fieldset;
/* TRES UTILISE POUR LES FORMULAIRES MULTI CONTEXTE */
/* if($tab_param['page']) {
$tab_contexte['page']=$tab_param['page'];
}
*/
$tab_param_form['url_action_form']=getControlerSetLink(getCLASSClassId(),$tab_contexte);
$tab_param_form['id_retour']=$tab_param['id_retour'];
$tab_param_form['submit_value'] = $tab_param['submit_value'];
$tab_param_form['popup'] = $tab_param['popup'];
$tab_param_form['redirect'] = $tab_param['redirect'];
$tab_param_form['target_attribut_id'] = $tab_param['target_attribut_id'];
$tab_param_form['target_attribut_lib'] = $tab_param['target_attribut_lib'];
$tab_param_form['id_class']= 'CLASS';
/* $tab_param_form['titre']='Titre';
$tab_param_form['sous-titre']='Sous titre';
*/
$html=getPresentationFormulaire($tab_attribut_valeur,$tab_param_form);
return $html;
}
Tiens, par exemple. Merci beaucoup en tout cas. :)
-
-
Essaye ces 4 lignes :
$tab = preg_replace('#"([^"]*)"#','"<span style="color:blue">$1</span>"', $tab); $tab = preg_replace("#([a-zA-Z]{3,}|\s)'([^']*)'#",'$1\'<span style="color:blue">$2</span>\'', $tab); $tab = preg_replace('#\/\*([^*]*)\*\/#','<span style="color:grey">/*$1*/</span>', $tab); $tab = preg_replace('#\/\*([^<]*)<span style="color:blue">([^<]*)</span>(.*)\*\/#msU', '/*$1<span style="color:grey">$2</span>$3*/', $tab);
Attention, cela ne fonctionne qu'avec une seule expression entourée de guillemet dans les commentaires.
Genre dans "/* Bonjour "toi" et "moi" */" seul le "toi" sera gris.-
-
Aie oui...
En fait pour éviter de colorier les apostrophe, je lui ai dit de prendre uniquement les guillemets précédé d'au moins 3 lettres (ça élimine les d', qu', c', etc...). Mais dans ce cas tout ce qui est ['montexte'] sera pris en compte...
La gestion des guillemets simples est vraiment galère. -
En repartant de ma coloration des guillemets, apostrophes et commentaires et de ta recolorisation des guillemets dans les commentaires :
$tab = preg_replace('#\/\*([^<]*)<span style="color:blue">([^<]*)</span>(.*)\*\/#msU', '/*$1<span style="color:grey">$2</span>$3*/', $tab);
J'obtiens ce que tu voulais me montrer à la base. Juste la première quote en gris. -
-
-
-
En fait, si tous tes commentaires sont au format /* ... */ (et pas en //) alors du peux faire un :
$parts = preg_split("#\/\*|\*\/#", $tab);
En gros tu éclates ta chaîne avec les "/*" ou les "*/" et tu génères un tableau.
À partir de ce moment-là, tu sais donc que :
$parts[0] : contient le début du texte
$parts[1] : contient le premier commentaire
$parts[2] : contient le texte entre les deux premiers commentaires
$parts[3] : contient le secondcommentaire
...
Donc les index pairs contiennent du texte normal et les index impairs du texte de commentaire. Dès lors tu peux reconstituer ton texte en appliquant les regexp qu'il faut.
$tab2 = ""; for ($i=0 ; $i<count($parts) ; $i++){ if ($i%2 == 0){ // Pair // Tu applique la regexp des guillemets $stringToAdd = preg_replace("#...#", "...", $parts[$i]); } else { // Impair > commentaire // Plus besoin de regexp : on colore en gris et on réinsère le pattern du split $stringToAdd = "<span style="color:grey;">/*" . $parts[$i] . "*/</span>"; } $tab2 .= $stringToAdd; }
Dis moi donc si ça tourne ^^-
Désolé, j'étais en pause bouffe. :[
Alors j'ai testé ton regex, ça m'a l'air de marcher !
$parts = preg_split('#\/\*|\*\/#', $tab); for ($i=0 ; $i<count($parts) ; $i++){ if ($i%2 == 0){ // Pair // Tu applique la regexp des guillemets $stringToAdd = preg_replace('#"(.*)"#msUi','<span style="color:blue">"$1"</span>', $parts[$i]); $stringToAdd = preg_replace('#\'(.*)\'#msUi','<span style="color:blue">"$1"</span>', $parts[$i]); } else { // Impair > commentaire // Plus besoin de regexp : on colore en gris et on réinsère le pattern du split $stringToAdd = '<span style="color:grey;">/*' . $parts[$i] . '*/</span>'; } $tab .= $stringToAdd; }
Je l'ai adapté à mon code et le seul souci c'est qu'il me retourne deux fois mon code, une fois sans aucune mise en forme et une fois pile comme je le voulais. Un petit souci que je devrais pouvoir résoudre si je me penche un peu dessus.
En tout cas, merci infiniment ! -
-
-
-
-
-
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question -
Pour ceux qui tomberont ici et qui comme moi ont galéré longtemps, je vous donne le code.
function replaceArray($tab){ // Mise en forme $tab = preg_replace('#;#',';<br/>', $tab); // Permet les retours à la ligne à la fin des commandes $tab = preg_replace('#{#','{<br/><BLOCKQUOTE>', $tab); // Permet les retours à la ligne et les tabulations lors des ouvertures d'accolades $tab = preg_replace('#}#','</BLOCKQUOTE>}<br/>', $tab); // Permet de supprimer les tabulations lors des fermetures d'accolades // Découpage de $tab en morceaux : le code et les commentaires $parts = preg_split('#\/\*|\*\/#', $tab); $tab=''; // On vide tab // Pour chaque morceau, on vérifie s'il s'agit de code ou de commentaire for ($i=0 ; $i<count($parts) ; $i++){ if ($i%2 == 0){ // Pair, c'est du code // Quotes en bleu, on fait les modifications voulues sur notre morceau de code $parts[$i] = preg_replace('#"(.*)"#msUi','<span style="color:blue">$0</span>', $parts[$i]); $parts[$i] = preg_replace('#\'(.*)\'#msUi','<span style="color:blue">$0</span>', $parts[$i]); } else { // Impair, c'est du commentaire // Commentaires en gris $parts[$i] = '<span style="color:grey;"><br/>/*' . $parts[$i] . '*/<br/></span>'; } $tab .= $parts[$i]; // Et on affecte notre morceau à tab, jusqu'à la fin de notre code } return $tab; } -
Par contre, j'étais en invité quand j'ai posté le sujet. Si un gentil modérateur/admin pouvait le passer en résolu, ce serait fort gentil !
Encore merci à Mihawk. Je te ferai une statue dans mon prochain jeu. o/