Convertir la balise de fermeture PHP en commentaire

149

Une des lignes de mon script contient une balise de fermeture PHP à l'intérieur d'une chaîne. En fonctionnement normal, cela ne pose pas de problème, mais je dois commenter la ligne.

J'ai essayé de commenter cette ligne avec //, /* */et #mais aucune d'entre elles ne fonctionne, l'analyseur considère la balise de fermeture comme une balise de fermeture réelle.

Voici la ligne en question:

$string = preg_replace('#<br\s*/?>(?:\s*<br\s*/?>)+#i', '<br />', $string);
//                              ^^             ^^

Que puis-je faire pour commenter la ligne ci-dessus?

v1n_vampire
la source
18
Problème drôle, mais réel. Je vote.
Voitcus
17
OMG. Au début, j'étais sceptique quant à votre question, prêt à demander quel était le problème, mais j'ai ensuite essayé de commenter une ligne avec une chaîne contenant '?>' Et je l'ai eu. Cela devrait être ajouté à la longue liste de phpsadness.com
lolesque
6
L'utilité d'une telle "fonctionnalité" est expliquée dans php.net/manual/en/language.basic-syntax.comments.php , elle est utile en cas de one-liner <?php # echo 'simple';?>.
lolesque
2
@lolesque Merci pour ce lien. Un bon. Un autre qui couvre également d'autres langues: wiki.theory.org/YourLanguageSucks
Simon Forsberg
5
@ OndraŽižka tout ce qu'il fait est de supprimer les balises br répétées. une regex fonctionne très bien pour cela. Ce n'est pas parce que parfois c'est mauvais que c'est mauvais tout le temps.
Kip

Réponses:

124

Utilisez une astuce: concaténez la chaîne de deux morceaux. De cette façon, la balise de fermeture est coupée en deux et n'est plus une balise de fermeture valide.'?>' --> '?'.'>'

Dans votre code:

$string = preg_replace('#<br\s*/?'.'>(?:\s*<br\s*/?'.'>)+#i', '<br />', $string);

Cela fera //fonctionner les commentaires.

Pour que les /* */commentaires fonctionnent, vous devez également diviser la */séquence:

$string = preg_replace('#<br\s*'.'/?'.'>(?:\s*<br\s*'.'/?'.'>)+#i', '<br />', $string);

Souvenez-vous, parfois, même si le tout est plus que la somme de ses parties - mais être gourmand est mauvais, il y a des moments où il vaut mieux en avoir moins . :)

ppeterka
la source
@ppeterka Wow, je n'y ai même pas pensé. Je vous remercie.
v1n_vampire
1
J'ai dû utiliser cette astuce en C il y a 2 jours pour une chaîne contenant??<
Ryan Amos
2
Elle est bonne. Pourquoi je ne pense jamais de cette façon!?
San
73

Le moyen le plus simple

Créez une variable distincte pour contenir votre expression régulière; de cette façon, vous pouvez simplement commenter la preg_replace()déclaration:

$re = '#<br\s*/?>(?:\s*<br\s*/?>)+#i';
// $string = preg_replace($re, '<br />', $string);

Correction en utilisant des classes de caractères

Pour corriger les commentaires de ligne, vous pouvez rompre ?>en insérant >une classe de caractères comme ceci:

$string = preg_replace('#<br\s*/?[>](?:\s*<br\s*/?[>])+#i', '<br />', $string);
                                 ^ ^              ^ ^

Pour corriger les commentaires de bloc, vous pouvez l'appliquer à /:

$string = preg_replace('#<br\s*[/]?>(?:\s*<br\s*[/]?>)+#i', '<br />', $string);
                               ^ ^              ^ ^

Pour corriger les deux styles de commentaire, vous pouvez mettre / et > dans leur propre classe de caractères.

Correction à l'aide du /xmodificateur

Le x modificateur - aka PCRE_EXTENDED- ignore les espaces et les retours à la ligne dans une expression régulière (sauf lorsqu'ils se produisent à l'intérieur d'une classe de caractères); cela permet d'ajouter des espaces pour séparer les caractères problématiques. Pour corriger les deux styles de commentaire:

$string = preg_replace('#<br\s* /? >(?:\s*<br\s* /? >)+#ix', '<br />', $string);
                               ^  ^             ^  ^
Jack
la source
@Cthulhu +1 (et pour la réponse aussi, bien sûr). De plus (du moins pour moi), cela rend l'expression rationnelle un peu plus difficile à comprendre. Pas de beaucoup, mais si je voyais cette expression régulière, je dirais: Hmmm, que se passe-t-il? Mais c'est carrément et totalement subjectif.
ppeterka
1
@ppeterka Je suis un peu d'accord, alors j'ai trouvé un autre moyen, en utilisant le xmodificateur :)
Ja͢ck
@Jack Nice, je donnerais un autre +1 pour cela, j'ai appris quelque chose de nouveau ... g
J'oublie constamment
@Jack Merci, j'apprends de nouvelles choses sur les regex grâce à la solution.
v1n_vampire
1
+1 pour séparer le regex sur une ligne antérieure. Il garde le regex le même, mais permet toujours à la logique d'être commentée.
38

Pourquoi vos tentatives n'ont pas fonctionné:

// $string = preg_replace('#<br\s*/?>(?:\s*<br\s*/?>)+#i',...
                                   ^ doesn't work due to ?> ending php

/* $string = preg_replace('#<br\s*/?>(?:\s*<br\s*/?>)+#i',... */
                                 ^ doesn't work due to */ closing comment

Ce qui fonctionne:

/* $string = preg_replace('#<br\s*[/]?>(?:\s*<br\s*[/]?>)+#i',... */
                                  ^ ^              ^ ^
// $string = preg_replace('#<br\s*/?[>](?:\s*<br\s*/?[>])+#i',...
                                    ^ ^              ^ ^

Plus loin...

Après ce qui précède, vous devriez pouvoir utiliser /*pour commenter la ligne. Si vous laissez ?>intact, //vous ne pouvez pas commenter une ligne entière. Le texte suivant ?>pourrait être html, qui est hors du contrôle de l'interpréteur PHP, donc cela ne fonctionnerait pas.

De la documentation:

Les styles de commentaire «une ligne» ne commentent que la fin de la ligne ou le bloc actuel de code PHP, selon la première éventualité. Cela signifie que le code HTML après // ...?> Ou # ...?> SERA imprimé:?> Sort du mode PHP et retourne en mode HTML, et // ou # ne peut pas influencer cela.

Anirudh Ramanathan
la source
Merci, tant de choses que je ne sais toujours pas ... C'est utile.
v1n_vampire
4
Ce post mériterait bien plus de +1 ... Rien que pour l'explication approfondie.
ppeterka
15

Une autre idée: échappez au >(et au /, si vous souhaitez utiliser un /*...*/commentaire):

$string = preg_replace('#<br\s*\/?\>(?:\s*<br\s*\/?\>)+#i', '<br />', $string);

Un échappement «inutile» est ignoré par le moteur de regex, mais est utile dans ce cas (pour les raisons exposées dans les autres réponses).

Tim Pietzcker
la source
@ppeterka: J'ai utilisé une barre oblique inverse au lieu d'une classe de caractères (mais oui, j'ai manqué une occurrence. Merci!)
Tim Pietzcker
Désolé, je suis fatigué ... J'ai remarqué le deuxième, qui a été laissé là-dedans entouré de [] ...
ppeterka
10

Pourquoi utiliser des «astuces» compliquées et difficiles à lire pour contourner le problème?

? est juste un raccourci quantificateur pour plus de commodité, donc

Utilisez simplement la version longue du quantificateur{0,1} , qui signifie "minimum 0 maximum 1 occurrence":

$string = preg_replace('#<br\s*/{0,1}>(?:\s*<br\s*/{0,1}>)+#i', '<br />', $string);
stema
la source
1
+1 cette page commence à être un très bon endroit pour rassembler des astuces de regex à garder dans notre esprit.
ppeterka
1
@ppeterka, j'appellerais en fait toutes les autres réponses des «trucs», mais ma réponse consiste simplement à utiliser la version longue du quantificateur et non le raccourci.
stema
3
Aucune offense, juste que dans mon dictionnaire, en utilisant la version longue d'une expression au lieu du sucre syntaxique plus court et plus pratique, on compte aussi comme un truc ...
ppeterka
8

Quelques autres façons à ajouter au livre d'astuces RegEx :

Tout d'abord, vous pouvez compacter votre RegEx en: /(<br\s*/?>)+/iet le remplacer par <br />(pas besoin de surcharger le RegExP avec des lookaheads) et vous vous retrouverez toujours avec le saut de ligne XHMTL que vous avez choisi.

Autres moyens de modifier votre RegEx afin qu'il ne déclenche pas le */commentaire de ?>fin ou le script de fin:

  • Utilisez des quantificateurs possessifs : #(<br\s*+/?+>)+#i- ce qui signifie essentiellement \s*+si vous avez trouvé que les espaces correspondent autant qu'il y en a et conservez-les, et /?+si vous avez trouvé une barre oblique, gardez-la!
  • Enclose \s*et /*en groupes de capture =>#(<br(\s*)(/?)>)+#i

Démos en direct: http://codepad.viper-7.com/YjqUbi

Et puisque nous avons penché le comportement possessif, le RegEx le plus rapide qui contourne également le problème des commentaires est: démo expliquée#(<br\s*+/?+>)++#i


Quant aux commentaires dans des situations délicates

Lorsque vous ne pouvez pas modifier le code, ou avez déjà utilisé un commentaire multiligne et:

1. Utilisez un nowdoc :

    $string='Hello<br>World<br><br />World<br><br><br>Word!';
    <<<'comment'
    $string = preg_replace('#(<br\s*/?>)+#i', '<br />', $string);
comment;

Code en direct: http://codepad.viper-7.com/22uOtV

Remarque: un nowdoc est similaire à un heredoc mais il n'analyse pas le contenu et doit avoir son séparateur de début entre 'guillemets simples '( notez que le délimiteur de fin ne peut pas être identifié , doit être suivi d' ;une nouvelle ligne ! )

2. Sautez le code avec un goto :

$string='Hello<br>World<br><br />World<br><br><br>Word!';
goto landing;
$string = preg_replace('#(<br\s*/?>)+#i', '<br />', $string);
landing:

Exemple en direct: http://codepad.viper-7.com/UfqrIQ

3. Sautez le code avec if(false)ou if(0):

$string='Hello<br>World<br><br />World<br><br><br>Word!';
if(0){
$string = preg_replace('#(<br\s*/?>)+#i', '<br />', $string);
}

Test: http://codepad.viper-7.com/wDg5H5

CSᵠ
la source