Expressions régulières pour coloration syntaxique [Résolu/Fermé]

Signaler
-
Messages postés
4310
Date d'inscription
mercredi 29 mars 2006
Statut
Contributeur
Dernière intervention
6 janvier 2015
-
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

Messages postés
4310
Date d'inscription
mercredi 29 mars 2006
Statut
Contributeur
Dernière intervention
6 janvier 2015
761
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 ?
Messages postés
17
Date d'inscription
jeudi 18 avril 2013
Statut
Membre
Dernière intervention
18 avril 2013

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.
Messages postés
4310
Date d'inscription
mercredi 29 mars 2006
Statut
Contributeur
Dernière intervention
6 janvier 2015
761
C'est le souci que j'ai soulevé au dessus :)
Messages postés
4310
Date d'inscription
mercredi 29 mars 2006
Statut
Contributeur
Dernière intervention
6 janvier 2015
761
À 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 !
Messages postés
17
Date d'inscription
jeudi 18 avril 2013
Statut
Membre
Dernière intervention
18 avril 2013

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. :)
Messages postés
17
Date d'inscription
jeudi 18 avril 2013
Statut
Membre
Dernière intervention
18 avril 2013

(Tu dois pouvoir en supprimer des morceaux si tu veux plus petit, mais au moins t'es sûr que si ça fonctionne pour ce pavé, ça fonctionne)
Messages postés
4310
Date d'inscription
mercredi 29 mars 2006
Statut
Contributeur
Dernière intervention
6 janvier 2015
761
Au fait je n'avais pas vu mais dans tes dernières regexp tu ne remplaces même plus le blue par du grey, et surtout tu ne refermes pas correctement le commentaire.
Messages postés
4310
Date d'inscription
mercredi 29 mars 2006
Statut
Contributeur
Dernière intervention
6 janvier 2015
761
Au fait, j'ai un autre cas en local : si jamais du meet un apostrophe dans un commentaire ça plante jusqu'au guillemet simple suivant ;)
Messages postés
17
Date d'inscription
jeudi 18 avril 2013
Statut
Membre
Dernière intervention
18 avril 2013

Pour le blue pas transformé en grey, je pensais simplement supprimer le blue, puisque le commentaire entier est en grey. Par contre je n'avais pas vu que je le fermais mal. Pour les apostrophes dans les commentaires, j'ai fini par mettre des back-ticks... x)
Messages postés
4310
Date d'inscription
mercredi 29 mars 2006
Statut
Contributeur
Dernière intervention
6 janvier 2015
761
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.
Messages postés
17
Date d'inscription
jeudi 18 avril 2013
Statut
Membre
Dernière intervention
18 avril 2013

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';
Messages postés
4310
Date d'inscription
mercredi 29 mars 2006
Statut
Contributeur
Dernière intervention
6 janvier 2015
761
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.
Messages postés
17
Date d'inscription
jeudi 18 avril 2013
Statut
Membre
Dernière intervention
18 avril 2013

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.
Messages postés
4310
Date d'inscription
mercredi 29 mars 2006
Statut
Contributeur
Dernière intervention
6 janvier 2015
761
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
Messages postés
17
Date d'inscription
jeudi 18 avril 2013
Statut
Membre
Dernière intervention
18 avril 2013

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.
Messages postés
4310
Date d'inscription
mercredi 29 mars 2006
Statut
Contributeur
Dernière intervention
6 janvier 2015
761
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 ^^
Messages postés
4310
Date d'inscription
mercredi 29 mars 2006
Statut
Contributeur
Dernière intervention
6 janvier 2015
761
Je n'ai pas trop compris quel était le problème ? Normalement les deux regexp ne matchent pas le même motif ça ne devrait donc pas s'annuler !
Messages postés
17
Date d'inscription
jeudi 18 avril 2013
Statut
Membre
Dernière intervention
18 avril 2013

En fait... $stringToAdd recevait un preg_replace de $parts[$i]. Lorsque j'en faisais un second, ça écrasait le premier (logique puisqu'il s'agit ici d'un simple =).

J'ai ensuite tenté ça :
$stringToAdd = preg_replace('#"(.*)"#msUi','<span style="color:blue">$0</span>', $parts[$i]);
			$stringToAdd .= preg_replace('#\'(.*)\'#msUi','<span style="color:blue">$0</span>', $parts[$i]);


Et ça ne fonctionnait pas non plus. Mais en fait, pour faire plusieurs transformations, il suffit de les écrire... dans $parts[$i].
			$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]);


Là, les transformations se font en direct, il n'y a donc pas d'écrasement. Dans ton cas, on sauvegardait la chaîne modifiée pour l'ajouter à $tab à la fin du if, donc si on souhaitait faire une deuxième modification, la chaîne changeait de valeur.

J'ai réussi à corriger ce petit problème, tu as fait le plus gros. Encore merci !
Messages postés
4310
Date d'inscription
mercredi 29 mars 2006
Statut
Contributeur
Dernière intervention
6 janvier 2015
761
Je t'en pris ; passe bien le sujet en résolu.
Messages postés
17
Date d'inscription
jeudi 18 avril 2013
Statut
Membre
Dernière intervention
18 avril 2013

J'aimerais, mais j'ai créé le post en invité, j'ai créé mon compte après. Du coup, je vais espérer qu'un gentil modérateur passe par ici, ou alors laisser le sujet couler.
Messages postés
4310
Date d'inscription
mercredi 29 mars 2006
Statut
Contributeur
Dernière intervention
6 janvier 2015
761
Je m'en occupe
Messages postés
17
Date d'inscription
jeudi 18 avril 2013
Statut
Membre
Dernière intervention
18 avril 2013

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;
}
Messages postés
17
Date d'inscription
jeudi 18 avril 2013
Statut
Membre
Dernière intervention
18 avril 2013

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/