Expressions régulières pour coloration syntaxique

Résolu/Fermé
Abyss - Modifié par Abyss le 17/04/2013 à 10:28
Mihawk Messages postés 4313 Date d'inscription mercredi 29 mars 2006 Statut Contributeur Dernière intervention 6 janvier 2015 - 18 avril 2013 à 16:50
Bonjour,

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

Mihawk Messages postés 4313 Date d'inscription mercredi 29 mars 2006 Statut Contributeur Dernière intervention 6 janvier 2015 845
17 avril 2013 à 22:26
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 ?
0
AbyssQuote Messages postés 17 Date d'inscription jeudi 18 avril 2013 Statut Membre Dernière intervention 18 avril 2013
18 avril 2013 à 09:44
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.
0
Mihawk Messages postés 4313 Date d'inscription mercredi 29 mars 2006 Statut Contributeur Dernière intervention 6 janvier 2015 845
18 avril 2013 à 09:48
C'est le souci que j'ai soulevé au dessus :)
0
Mihawk Messages postés 4313 Date d'inscription mercredi 29 mars 2006 Statut Contributeur Dernière intervention 6 janvier 2015 845
18 avril 2013 à 09:53
À 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 !
0
AbyssQuote Messages postés 17 Date d'inscription jeudi 18 avril 2013 Statut Membre Dernière intervention 18 avril 2013
18 avril 2013 à 10:23
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.
0
Mihawk Messages postés 4313 Date d'inscription mercredi 29 mars 2006 Statut Contributeur Dernière intervention 6 janvier 2015 845
Modifié par Mihawk le 18/04/2013 à 10:44
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 '/'
0
AbyssQuote Messages postés 17 Date d'inscription jeudi 18 avril 2013 Statut Membre Dernière intervention 18 avril 2013
18 avril 2013 à 10:47
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.
0
Mihawk Messages postés 4313 Date d'inscription mercredi 29 mars 2006 Statut Contributeur Dernière intervention 6 janvier 2015 845
18 avril 2013 à 10:49
L'exercice auquel tu t'essaye n'est pas simple.
Tu pourrais me passer un bout de texte à colorier ? Je vais tester ça en local.
0
AbyssQuote Messages postés 17 Date d'inscription jeudi 18 avril 2013 Statut Membre Dernière intervention 18 avril 2013
18 avril 2013 à 11:05
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. :)
0
Mihawk Messages postés 4313 Date d'inscription mercredi 29 mars 2006 Statut Contributeur Dernière intervention 6 janvier 2015 845
18 avril 2013 à 11:19
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.
0
AbyssQuote Messages postés 17 Date d'inscription jeudi 18 avril 2013 Statut Membre Dernière intervention 18 avril 2013
18 avril 2013 à 11:27
Ca me fait pas loin du contraire. Lorsqu'il rencontre un ' ou " dans un commentaire, il met la suite du commentaire en bleu. Et pour les guillemets et apostrophes en dehors des commentaires, ça me fait un truc bizarre.
$tab_fieldset['0']['legend'<span style="color:blue">]=</span>'LEGEND 0';
0
Mihawk Messages postés 4313 Date d'inscription mercredi 29 mars 2006 Statut Contributeur Dernière intervention 6 janvier 2015 845
18 avril 2013 à 11:30
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.
0
AbyssQuote Messages postés 17 Date d'inscription jeudi 18 avril 2013 Statut Membre Dernière intervention 18 avril 2013
18 avril 2013 à 11:34
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.
0
Mihawk Messages postés 4313 Date d'inscription mercredi 29 mars 2006 Statut Contributeur Dernière intervention 6 janvier 2015 845
18 avril 2013 à 12:01
Oui en fait le preg replace ne fonctionne pas dans notre cas... Il faudrait plutôt faire un "explode" de ton texte afin de traiter chaque partie indépendamment
0
AbyssQuote Messages postés 17 Date d'inscription jeudi 18 avril 2013 Statut Membre Dernière intervention 18 avril 2013
18 avril 2013 à 12:06
Je pensais que ça passerait avec un while, mais non plus.
Je suis très mauvais en algo, tu veux faire un explode(" ",$tab), ok. Et ensuite un foreach sur l'array obtenu ? Si oui, ça pose souci, parce que ma fonction prend un $string en entrée et retournera un array. Je suis pas sûr qu'il apprécie.
0
Mihawk Messages postés 4313 Date d'inscription mercredi 29 mars 2006 Statut Contributeur Dernière intervention 6 janvier 2015 845
18 avril 2013 à 13:00
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 ^^
0
AbyssQuote Messages postés 17 Date d'inscription jeudi 18 avril 2013 Statut Membre Dernière intervention 18 avril 2013
18 avril 2013 à 14:45
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 !
0
Mihawk Messages postés 4313 Date d'inscription mercredi 29 mars 2006 Statut Contributeur Dernière intervention 6 janvier 2015 845
18 avril 2013 à 14:48
Normalement mon code l'affiche une fois coloré.
S'il s'affiche 2 fois c'est que tu n'as pas supprimé un echo de ton côté je pense :)
0
AbyssQuote Messages postés 17 Date d'inscription jeudi 18 avril 2013 Statut Membre Dernière intervention 18 avril 2013
18 avril 2013 à 15:17
Au temps pour moi, j'avais supprimé ton $tab2="".

Ce que je trouve étrange c'est que lorsque je rajoute une simple ligne de code dans le pair :
$stringToAdd = preg_replace('#(function)#msUi','<span style="color:purple">$0</span>', $parts[$i]);


Tout le bleu disparait au profit de function en violet.
0
AbyssQuote Messages postés 17 Date d'inscription jeudi 18 avril 2013 Statut Membre Dernière intervention 18 avril 2013
18 avril 2013 à 15:33
Je vois d'où ça vient. Ca réécrit par dessus. Pas de souci de ce côté là, suffit de le mettre à la suite. Merci encore !
0
Mihawk Messages postés 4313 Date d'inscription mercredi 29 mars 2006 Statut Contributeur Dernière intervention 6 janvier 2015 845
18 avril 2013 à 15:34
Avec ça ?

$stringToAdd = preg_replace('#(function)#i','<span style="color:purple">$1</span>', $parts[$i]);
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
AbyssQuote Messages postés 17 Date d'inscription jeudi 18 avril 2013 Statut Membre Dernière intervention 18 avril 2013
18 avril 2013 à 15:57
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;
}
0
AbyssQuote Messages postés 17 Date d'inscription jeudi 18 avril 2013 Statut Membre Dernière intervention 18 avril 2013
18 avril 2013 à 16:00
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/
0