Converti il ​​tag di chiusura PHP in commento


149

Una delle righe nel mio script contiene un tag di chiusura PHP all'interno di una stringa. Durante il normale funzionamento ciò non causa problemi, ma devo commentare la riga.

Ho cercato di commentare questa linea con //, /* */e #ma nessuno di loro lavoro, il parser considera tag di chiusura di essere un tag di chiusura effettiva.

Ecco la linea in questione:

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

Cosa posso fare per commentare la riga sopra?


18
Problema divertente, ma reale. Voto in alto.
Voitcus

17
OH MIO DIO. All'inizio ero scettico sulla tua domanda, pronto a chiedere qual era il problema, ma poi ho provato a commentare una riga con una stringa contenente "?>" E l'ho capito. Questo dovrebbe essere aggiunto alla lunga lista di phpsadness.com
lolesque

6
L'utilità di tale "caratteristica" è spiegata in php.net/manual/it/language.basic-syntax.comments.php , è utile in caso di una riga <?php # echo 'simple';?>.
Lolesque,

2
@lolesque Grazie per quel link. Una buona. Una correlata che copre anche altre lingue: wiki.theory.org/YourLanguageSucks
Simon Forsberg

5
@ OndraŽižka non fa altro che rimuovere tag br ripetuti. un regex funziona bene per questo. Solo perché a volte fa male non significa che sia sempre male.
Kip

Risposte:


124

Usa un trucco: concatena la corda da due pezzi. In questo modo, il tag di chiusura viene tagliato in due e non è più un tag di chiusura valido.'?>' --> '?'.'>'

Nel tuo codice:

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

Questo farà //funzionare i commenti.

Affinché i /* */commenti funzionino, dovresti dividere anche la */sequenza:

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

Ricorda, a volte, anche se il tutto è più della somma delle sue parti - ma essere avidi è male, ci sono volte che è meglio lasciarti con meno . :)


@ppeterka Wow, non ci ho nemmeno pensato. Grazie.
v1n_vampire

1
Ho dovuto usare questo trucco in C 2 giorni fa per una stringa contenente??<
Ryan Amos il

2
Grande. Perché non la penso mai così !?
San

73

La via più facile

Crea una variabile separata per contenere la tua espressione regolare; in questo modo puoi semplicemente commentare l' preg_replace()affermazione:

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

Risolto usando le classi di caratteri

Per correggere i commenti di riga, puoi interrompere ?>inserendo >una classe di caratteri in questo modo:

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

Per correggere i commenti di blocco, puoi applicarlo a /:

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

Per correggere entrambi gli stili di commento, puoi mettere / e > nella loro classe di caratteri.

Risolto usando il /xmodificatore

Il x modificatore - aka PCRE_EXTENDED- ignora gli spazi e le nuove righe in un'espressione regolare (tranne quando si verificano all'interno di una classe di caratteri); questo rende possibile aggiungere spazi per separare i caratteri problematici. Per correggere entrambi gli stili di commento:

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

@Cthulhu +1 (e anche per la risposta, ovviamente). Inoltre (almeno per me) questo rende il regexp un po 'più difficile da capire. Non di molto, ma se vedessi questa regex, direi: Hmmm, che sta succedendo? Ma questo è decisamente e totalmente soggettivo.
ppeterka,

1
@ppeterka Sono abbastanza d'accordo, quindi ho trovato un altro modo, usando il xmodificatore :)
Ja͢ck

@Jack Nice, darei un altro +1 per questo, ho imparato qualcosa di nuovo ... Continuo a dimenticare i modificatori regex (li uso raramente a parte g) ...
ppeterka

@Jack Grazie, ho imparato cose nuove su regex dalla soluzione.
v1n_vampire

1
+1 per separare la regex su una riga precedente. Mantiene la regex la stessa, ma consente comunque di commentare la logica.

38

Perché i tuoi tentativi non hanno funzionato:

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

Cosa funziona:

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

Ulteriore...

Dopo quanto sopra, dovresti essere in grado di utilizzare /*per commentare la riga. Se si lascia ?>intatto, //non è possibile commentare un'intera riga. Il seguente testo ?>potrebbe essere html, che è fuori dal controllo dell'interprete PHP, quindi non funzionerebbe.

Dalla documentazione:

Gli stili di commento "a riga singola" commentano solo la fine della riga o il blocco corrente di codice PHP, a seconda di quale si verifichi per primo. Ciò significa che il codice HTML dopo // ...?> O # ...?> Verrà stampato:?> Esce dalla modalità PHP e ritorna alla modalità HTML e // o # non possono influenzarlo.


Grazie, tante cose che ancora non so ... È utile.
v1n_vampire

4
Questo post meriterebbe molti più +1 ... Solo per la spiegazione approfondita.
ppeterka,

15

Un'altra idea: sfuggire al >(e al /, se si desidera utilizzare un /*...*/commento):

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

Una fuga "non necessaria" viene ignorata dal motore regex, ma è utile in questo caso (per i motivi indicati nelle altre risposte).


@ppeterka: ho usato una barra rovesciata anziché una classe di caratteri (ma sì, mi sono perso un episodio. Grazie!)
Tim Pietzcker

Scusa, sembra che sono stanco ... Ho notato il secondo, che è stato lasciato lì dentro circondato da [] ...
ppeterka

10

Perché usare "trucchi" complicati e difficili da leggere per aggirare il problema?

? è solo una scorciatoia da quantificatore per comodità, quindi

Basta usare la versione lunga del quantificatore{0,1} , significa "minimo 0 massimo 1 occorrenza":

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

1
+1 questa pagina inizia ad essere un ottimo posto per raccogliere trucchi regex da tenere nella parte posteriore della nostra mente.
ppeterka,

1
@ppeterka, in realtà chiamerei tutte le altre risposte "trucchi", ma la mia risposta sta usando solo la versione lunga del quantificatore e non il collegamento.
Stema

3
Senza offesa, solo questo nel mio dizionario, usando la versione lunga di un'espressione invece dello zucchero sintattico più breve e più conveniente uno conta anche come un trucco ...
ppeterka

8

Alcuni altri modi che vale la pena aggiungere al libro dei trucchi RegEx :

Per prima cosa potresti compattare il tuo RegEx in: /(<br\s*/?>)+/ie sostituirlo con <br />(non è necessario caricare il RegExP con lookaheads) e finirai sempre con l'interruzione di linea XHMTL scelta.

Altri modi per modificare RegEx in modo che non inciampi nel */commento ?>finale o nello script finale:

  • Usa quantificatori possessivi : #(<br\s*+/?+>)+#i- che in pratica significano \s*+se hai trovato spazi bianchi quanti ne esistono e conservali, e per/?+ se hai trovato una barra tienilo!
  • Racchiudere \s*e /*in gruppi di acquisizione =>#(<br(\s*)(/?)>)+#i

Demo live: http://codepad.viper-7.com/YjqUbi

E dal momento che abbiamo appoggiato il comportamento possessivo, il RegEx più veloce che aggira anche il problema dei commenti è: spiegato demo#(<br\s*+/?+>)++#i


Per quanto riguarda i commenti in situazioni difficili

Quando non puoi cambiare il codice o hai già usato un commento su più righe e:

1. Usa un nowdoc :

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

Codice live: http://codepad.viper-7.com/22uOtV

Nota: un nowdoc è simile a un heredoc ma non analizza il contenuto e deve avere il delimitatore iniziale racchiuso tra 'virgolette singole '( nota che il delimitatore finale non può essere identificato , deve essere seguito da ;una nuova riga ! )

2. Salta il codice con un goto :

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

Esempio live: http://codepad.viper-7.com/UfqrIQ

3. Salta il codice con if(false)o 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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.