Converter tag de fechamento PHP em comentário

149

Uma das linhas do meu script contém uma tag de fechamento do PHP dentro de uma string. Sob operação normal, isso não causa problemas, mas preciso comentar a linha.

Tentei comentar esta linha com //, /* */e #mas nenhum deles trabalho, o analisador considera fechando tag para ser um tag de encerramento efectivo.

Aqui está a linha em questão:

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

O que posso fazer para comentar a linha acima?

v1n_vampire
fonte
18
Problema engraçado, mas real. Eu voto.
Voitcus 5/03/2013
17
AMD. No começo, eu era cético em relação à sua pergunta, pronto para perguntar qual era o problema, mas depois tentei comentar uma linha com uma string contendo '?>' E entendi. Isso deve ser adicionado à longa lista de phpsadness.com
lolesque
6
A utilidade desse "recurso" é explicada em php.net/manual/en/language.basic-syntax.comments.php , é útil no caso de uma linha <?php # echo 'simple';?>.
Lolsque 5/03
2
@lolesque Obrigado por esse link. Uma boa. A um relacionado que abrange outras línguas também: wiki.theory.org/YourLanguageSucks
Simon Forsberg
5
@ OndraŽižka tudo o que ele está fazendo é remover repetidas tags br. um regex funciona bem para isso. Só porque é ruim às vezes não significa que é ruim o tempo todo.
Kip

Respostas:

124

Use um truque: concatene a corda de duas peças. Dessa forma, a tag de fechamento é cortada em duas e não é mais uma tag de fechamento válida.'?>' --> '?'.'>'

No seu código:

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

Isso fará com que os //comentários funcionem.

Para que os /* */comentários funcionem, você também precisará dividir a */sequência:

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

Lembre-se, às vezes, mesmo que o todo seja mais do que a soma de suas partes - mas ser ganancioso é ruim, há momentos em que é melhor você ficar com menos . :)

ppeterka
fonte
@ppeterka Uau, eu nem pensei nisso. Obrigado.
V1n_vampire
1
Eu tive que usar esse truque em C 2 dias atrás para uma string contendo??<
Ryan Amos
2
Muito bom. Por que nunca penso assim !?
San
73

A maneira mais fácil

Crie uma variável separada para manter sua expressão regular; Dessa forma, você pode simplesmente comentar a preg_replace()declaração:

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

Corrigir usando classes de caracteres

Para corrigir comentários de linha, você pode terminar ?>colocando >uma classe de caractere assim:

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

Para corrigir comentários em bloco, você pode aplicá-lo a /:

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

Para corrigir os dois estilos de comentários, você pode colocar / e > em sua própria classe de caracteres.

Corrigir usando o /xmodificador

O x modificador - aka PCRE_EXTENDED- ignora espaços e novas linhas em uma expressão regular (exceto quando ocorrem dentro de uma classe de caracteres); isso torna possível adicionar espaços para separar os caracteres problemáticos. Para corrigir os dois estilos de comentário:

$string = preg_replace('#<br\s* /? >(?:\s*<br\s* /? >)+#ix', '<br />', $string);
                               ^  ^             ^  ^
Ja͢ck
fonte
@Cthulhu +1 (e também para a resposta, é claro). Além disso (pelo menos para mim), isso torna o regexp um pouco mais difícil de entender. Não muito, mas se eu visse esse regex, diria: Hmmm, o que está acontecendo? Mas isso é francamente e totalmente subjetivo.
ppeterka
1
@ppeterka eu concordo um pouco, então eu encontrei outra maneira, usando o xmodificador :)
Jack
@Jack agradável, eu daria outra +1 para ele, eu aprendi algo novo ... Eu continuo esquecendo os modificadores de regex (eu raramente usá-los para além de g) ...
ppeterka
@ Jack Obrigado, aprendo coisas novas sobre regex a partir da solução.
V1n_vampire
1
+1 para separar a expressão regular em uma linha anterior. Ele mantém a regex igual, mas ainda permite que a lógica seja comentada.
38

Por que suas tentativas não funcionaram:

// $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

O que funciona:

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

Mais distante...

Após o exposto, você poderá usar /*para comentar a linha. Se você deixar ?>intacto, //não poderá comentar uma linha inteira. O texto a seguir ?>pode ser html, que está fora do controle do interpretador PHP, para que não funcione.

A partir da documentação:

Os estilos de comentário "uma linha" comentam apenas o final da linha ou o bloco atual do código PHP, o que ocorrer primeiro. Isso significa que o código HTML após // ...?> Ou # ...?> Será impresso:?> Sairá do modo PHP e retornará ao modo HTML, e // ou # não poderá influenciar isso.

Anirudh Ramanathan
fonte
Obrigado, tantas coisas que ainda não sei ... É útil.
precisa saber é o seguinte
4
Esta postagem mereceria muito mais + 1s ... Apenas para uma explicação completa.
ppeterka
15

Outra idéia: escape do >(e do /, se você quiser usar um /*...*/comentário):

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

Uma fuga "desnecessária" é ignorada pelo mecanismo regex, mas é útil neste caso (por razões descritas nas outras respostas).

Tim Pietzcker
fonte
@ppeterka: Eu usei uma barra invertida em vez de uma classe de personagem (mas sim, eu sentia falta de uma ocorrência Graças.!)
Tim Pietzcker
Desculpe, parece que eu estou cansado ... Eu observei o segundo, que foi deixado lá cercado com [] ...
ppeterka
10

Por que usar "truques" complicados e difíceis de ler para solucionar o problema?

? é apenas um atalho de quantificador por conveniência, então

Basta usar a versão longa do quantificador{0,1} , significa "mínimo 0 máximo 1 ocorrência":

$string = preg_replace('#<br\s*/{0,1}>(?:\s*<br\s*/{0,1}>)+#i', '<br />', $string);
stema
fonte
1
Marcar com +1 essa página começa a ser um ótimo lugar para reunir truques de regex para manter em mente.
ppeterka
1
@ppeterka, eu realmente chamaria todas as outras respostas de "truques", mas minha resposta é apenas usar a versão longa do quantificador e não o atalho.
stema
3
Sem ofensa, só que no meu dicionário, utilizando a versão longa de uma expressão em vez dos mais curtos, mais conveniente sintática açúcar se conta como um truque também ...
ppeterka
8

Vale a pena acrescentar algumas outras maneiras ao livro de truques RegEx :

Primeiro você pode compactar seu RegEx para: /(<br\s*/?>)+/ie substituir por<br /> (não é necessário sobrecarregar o RegExP com olhais) e você sempre terminará com a quebra de linha XHMTL escolhida.

Outras maneiras de modificar o seu RegEx para que ele não tropeça no */comentário ?>final ou no script final:

  • Use quantificadores possessivos : #(<br\s*+/?+>)+#i- o que significa basicamente \s*+se você encontrou espaço em branco igual a tantos quantos existem e o mantém, e /?+se você encontrou uma barra, mantenha-o!
  • Coloque \s*e /*em grupos de captura =>#(<br(\s*)(/?)>)+#i

Demonstrações ao vivo: http://codepad.viper-7.com/YjqUbi

E, como adotamos o comportamento possessivo, o RegEx mais rápido, que também contorna o problema dos comentários, é: demonstração explicada#(<br\s*+/?+>)++#i


Quanto a comentar em situações difíceis

Quando você não pode alterar o código ou já usou um comentário de várias linhas e:

1. Use um nowdoc :

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

Código ao vivo: http://codepad.viper-7.com/22uOtV

Nota: um nowdoc é semelhante a um heredoc, mas não analisa o conteúdo e deve incluir o delimitador inicial entre 'aspas simples '( observe que o delimitador final não pode ser identificado , deve ser seguido por ;uma nova linha ! )

2. Pule o código com um goto :

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

Exemplo ao vivo: http://codepad.viper-7.com/UfqrIQ

3. Passe o mouse sobre o código com 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);
}

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

CSᵠ
fonte