Regex pour les PHP men

WRInaute occasionnel
Salut,

J'ai un souci que j'arrive pas à régler, si un spécialiste des regex passe dans le coin.

j'ai ça :
Code:
preg_match_all('#<code>(.*)</code>#', $chaine, $tab);
Vous l'avez compris, je développe une fonction de colorisation de code pour un blog.

Après je fais mes traitements, ça marche nickel, sauf si j'ai des sauts de ligne dans le code ! c'est ballot quand même...

Ca fonctionne

Code:
<code><?php echo 'Hello World'; ?></code>
Ca fonctionne pas

Code:
<code>
<?php
echo 'Hello World';
echo 'I need some Help';
?>
</code>
Il faut que j'intègre dans mon regex les sauts de ligne et consorts, et je bloque là dessus.

Si quelqu'un peut me donner un coup de main, ce serait sympa.

Merci.
 
WRInaute occasionnel
n'oublie pas d'échapper ton slash dans ta regex ( le faire précéder d'un antislash)...
Et pourquoi preg_match_all tu peux pas faire preg_match ?
 
WRInaute discret
Bonjour,
essaie d'utiliser l'option "s" (afin que le point reconnaisse les retours à la ligne).

Ce qui donnerait :
Code:
preg_match_all('#<code>(.*)</code>#s', $chaine, $tab);

PS. il existe d'autres options qui devraient t'intéresser : l'option "i" pour rendre insensible à la casse, l'option "U" (ungreedy = non gourmande) qui pourrait t'être utile en cas d'enchevêtrement de balises...
 
WRInaute discret
J'avais complètement oublié l'existence de l'option multilignes LOL
Le lien de Seebz est parfait !
 
WRInaute impliqué
Je te conseil d'utiliser l'option "U" aussi (PCRE_UNGREEDY).
Sinon, tu risques d'avoir des problèmes avec du texte de ce genre :
Code:
Voici mon premier exemple :
<code>
<?php
echo 'Hello World';
echo 'I need some Help';
?>
</code>

Et pour finir, le deuxième :
<code>
<?php
echo 'Hello World, le retour';
?>
</code>

Les parenthèses vont capturer ceci (sans U) :
Code:
<?php
echo 'Hello World';
echo 'I need some Help';
?>
</code>

Et pour finir, le deuxième :
<code>
<?php
echo 'Hello World, le retour';
?>

Normalement, avec "imsU", tu ne devrais pas avoir de problème. Sachant que "i" est optionnel (pour la casse).

michel.leonard a dit:
n'oublie pas d'échapper ton slash dans ta regex ( le faire précéder d'un antislash)...
Et pourquoi preg_match_all tu peux pas faire preg_match ?
Je ne vois pas pourquoi le slashes devrait être échappé. Il n'a pas de signification dans une regexp.
 
WRInaute occasionnel
Oulala, merci à tous pour ces réponses !

Je suis pas très à l'aise avec les REGEX, j'ai peu de temps à y consacrer et pourtant j'en utilise régulièrement. Je vais tenter de répondre à tout le monde.

michel.leonard a dit:
n'oublie pas d'échapper ton slash dans ta regex ( le faire précéder d'un antislash)...
Et pourquoi preg_match_all tu peux pas faire preg_match ?
Parce que je veux isoler plusieurs blocs potentiels dans un même article, sans qu'ils se télescopes. Après j'applique d'autres traitements sur le array() que la fonction retourne.
J'ai rajouté le slash, merci, un oubli.

spout a dit:
TROLL: parce que le JS c'est mal
Très de plaisanterie, j'évite au maximum d'alourdir les pages avec des librairies JS. J'en utilise une pour rendre le code de l'éditeur du backOffice plus lisible, mais en front, place à la performance.
Déjà que je load JQuery et quelques plugins (lightbox par exemple, calendar UI...), je préfère limiter au maximum.

Et j'ai donc réglé mon problème grâce à votre aide et je vous en remercie vraiment.

La solution est celle de Blount avec "imsU".

Car si je n'utilise que certaines de ces options, il y a toujours un cas de figure qui merdouille. Notamment lorsqu'il y a plusieurs blocs <code> dans un même article, il les fusionne.

Pour ceux que ça intéresse, voici le code :
Code:
<?php
// Highlight code
preg_match_all('#<code>(.*)<\/code>#imsU', $chaine, $tab);

if(count($tab[1]) > 0)
{
	$resultab = array_values(array_unique($tab[1])); // Suppression des doublons + recalcul des clés du array()

	$code = array();
	foreach($resultab as $v)
	{
		$code[] = preg_replace('#<code>#', '', highlight_code($v));
	}
	$chaine = str_replace(array_values($resultab), array_values(preg_replace('#</code>#', '', $code)), $chaine);
	return $chaine;
}
else return $chaine;
?>
Le "highlight_code($v)" correspond à une fonction du framework PHP de Codeigniter 2.0.1 pour ceux qui voudraient la récupérer.
Il me reste un problème (plutôt de performance pour le coup), c'est que le regex me réinjecte les balises <code></code> et que me fonction PHP les ajoute également (comportement que je ne souhaite pas modifier pour diverses raisons).

C'est ce qui explique je j'utilise par deux fois un preg_replace pour retirer les balises <code> et </code> en doublon. Si quelqu'un a une idée...

Sinon, c'est là que l'on voit l'intérêt du preg_match_all et de la fonction qui suit, car si plusieurs blocs dans un article, tu fusionnes tout.

J'utilise une fonction similaire pour rajouter un chemin absolu sur un cookieless domain aux images qui sont ajoutées depuis KCFinder. Toujours pour une question de performances. A l'enregistrement de l'article, j'ajoute ça dans la balise IMG qui n'en n'a pas, plutôt que d'utiliser des chemins relatifs moins performants.

Voilà une affaire rondement menée, merci encore !

Bon WE
 
WRInaute impliqué
Premièrement, enlève l'antislash devant le slash.
Ce n'est pas un caractère spécial, la preuve :
Code:
jerome@jerome:~$ php -r "echo preg_quote('.').\"\n\";"
\.
jerome@jerome:~$ php -r "echo preg_quote('/').\"\n\";"
/
On voit bien qu'il protège le point, mais pas le slash.


Ensuite, regarde du coté de preg_replace_callback.
Pour chaque correspondance, il va appeler une fonction pour remplacer la chaîne par ce que tu veux.

Tu n'as plus qu'à créer une fonction pour colorer ton code. Cette fonction peux même être "highlight_code".
En clair, tout ton code pourrait ressembler à ceci:
Code:
$chaine = preg_replace_callback('#<code>(.*)</code>#imsU', 'highlight_code', $chaine)
Ça simplifierait ton code.
 
WRInaute occasionnel
Salut,

Merci pour l'info, j'avais testé cette fonction, mais je n'avais pas pensé à appeler directement la fonction de mon framework depuis preg_replace_callback()

Je vais testé, effectivement, c'est plus simple, mais est ce que je vais obtenir le résultat souhaité. Mystère.

Je posterai en début dès que j'aurais fait l'essai.

Merci et bon WE.
 
WRInaute discret
Salut,

Pour le regex, je dirais :

Code:
/<code>.*?<\/code>/is

n'oublies pas de doubler le backslash dans php

il faut bien mettre le point d'interrogation pour que le remplacement se fasse en mode ungreedy (non gourmand) sinon tu auras un problème avec ce genre de situation:

Code:
<code>blabla</code>
blabla
<code>blabla</code>
blabla

qui deviendra

Code:
<code>remplacement</code>
blabla

@+
 
WRInaute occasionnel
Bonjour,

Merci à tous pour votre aide, comme indiqué dans un précédent topic, la solution a été trouvée.

Finalement, l'utilisation de la fonction preg_replace_callback ne convient pas, j'ai conservé mon code (j'avais des array au mileu de string, pas gérable).

Le code indiqué plus haut fonctionne très bien, il n'est pas très élégant, mais ça fonctionne et ça ne pompe pas trop de ressources, surtout que les pages sont mises à en cache de façon définitive, sauf modification dans le backOffice.

@stephdim : dans le cas présent, .*? ne fonctionne pas, ça me regroupe les blocs <code> en un seul et me sème la pagaille. Merci quand même de l'idée, fonctionnelle si un seul bloc.

Bonne semaine ;-)
 
Discussions similaires
Haut