Ubah tag penutup PHP menjadi komentar

149

Salah satu baris dalam skrip saya berisi tag penutup PHP di dalam sebuah string. Dalam operasi normal ini tidak menimbulkan masalah, tetapi saya perlu mengomentari baris.

Saya telah mencoba untuk mengomentari baris ini dengan //, /* */dan #tetapi tidak satupun dari mereka bekerja, parser menganggap tag penutup sebagai tag penutup yang sebenarnya.

Inilah baris yang dimaksud:

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

Apa yang bisa saya lakukan untuk mengomentari baris di atas?

v1n_vampire
sumber
18
Masalah lucu, tapi nyata. Saya memilih.
Voitcus
17
OH TUHAN. Awalnya saya ragu dengan pertanyaan Anda, siap bertanya apa masalahnya, tetapi kemudian saya mencoba mengomentari baris dengan string yang berisi '?>' Dan saya mendapatkannya. Ini harus ditambahkan ke daftar panjang phpsadness.com
lolesque
6
Kegunaan dari "fitur" tersebut dijelaskan dalam php.net/manual/en/language.basic-syntax.comments.php , ini berguna untuk one-liner <?php # echo 'simple';?>.
lolesque
2
@lolesque Terima kasih atas tautannya. Salah satu yang baik. Yang terkait yang mencakup bahasa lain juga: wiki.theory.org/YourLanguageSucks
Simon Forsberg
5
@ OndraŽižka yang dia lakukan hanyalah menghapus tag br berulang. sebuah regex berfungsi dengan baik untuk itu. Hanya karena itu buruk kadang-kadang tidak berarti itu buruk sepanjang waktu.
Kip

Jawaban:

124

Gunakan trik: menyatukan string dari dua bagian. Dengan cara ini, tag penutup dipotong menjadi dua, dan bukan tag penutup yang valid lagi.'?>' --> '?'.'>'

Dalam kode Anda:

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

Ini akan membuat // komentar berfungsi.

Agar /* */komentar berfungsi, Anda harus membagi */urutannya juga:

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

Ingat, kadang-kadang, meskipun keseluruhan lebih dari jumlah bagian-bagiannya - tetapi menjadi serakah itu buruk, ada kalanya Anda lebih baik dibiarkan kurang . :)

ppeterka
sumber
@ peterka Wow, saya bahkan tidak memikirkannya. Terima kasih.
v1n_vampire
1
Saya harus menggunakan trik ini dalam C 2 hari yang lalu untuk string yang mengandung??<
Ryan Amos
2
Bagus Kenapa aku tidak pernah berpikir seperti itu !?
San
73

Cara termudah

Buat variabel terpisah untuk menahan ekspresi reguler Anda; dengan cara ini Anda cukup mengomentari preg_replace()pernyataan:

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

Perbaiki menggunakan kelas karakter

Untuk memperbaiki komentar baris, Anda dapat memecahnya ?>dengan memasukkan ke >dalam kelas karakter seperti:

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

Untuk memperbaiki komentar blokir, Anda dapat menerapkannya pada /:

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

Untuk memperbaiki kedua gaya komentar, Anda dapat menempatkan / dan > di kelas karakter mereka sendiri.

Perbaiki menggunakan /xpengubah

The x pengubah - alias PCRE_EXTENDED- abaikan ruang dan baris baru dalam ekspresi reguler (kecuali ketika mereka terjadi di dalam kelas karakter); ini memungkinkan untuk menambahkan spasi untuk memisahkan karakter yang bermasalah. Untuk memperbaiki kedua gaya komentar:

$string = preg_replace('#<br\s* /? >(?:\s*<br\s* /? >)+#ix', '<br />', $string);
                               ^  ^             ^  ^
Mendongkrak
sumber
@Cthulhu +1 (dan untuk jawabannya juga, tentu saja). Juga (setidaknya untuk saya) ini membuat regexp sedikit lebih sulit untuk dipahami. Tidak banyak, tetapi jika saya melihat regex ini, saya akan mengatakan: Hmmm, apa yang terjadi? Tapi itu benar-benar subjektif dan subjektif.
ppeterka
1
@ppeterka Saya agak setuju, jadi saya menemukan cara lain, dengan menggunakan xpengubah :)
Ja͢ck
@ Jack Nice, saya akan memberikan +1 lagi untuk itu, saya telah mempelajari sesuatu yang baru ... Saya selalu lupa tentang pengubah regex (saya jarang menggunakannya selain g) ...
ppeterka
@ Jack Terima kasih, saya belajar hal-hal baru tentang regex dari solusinya.
v1n_vampire
1
+1 untuk memisahkan regex ke baris sebelumnya. Itu membuat regex tetap sama, tetapi masih memungkinkan logika untuk dikomentari.
38

Mengapa upaya Anda tidak berhasil:

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

Pekerjaan apa:

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

Lebih lanjut...

Setelah hal di atas, Anda dapat menggunakan /*komentar di luar garis. Jika Anda membiarkannya ?>utuh, //tidak mungkin mengomentari seluruh baris. Teks berikut?> bisa berupa html, yang berada di luar kendali penerjemah PHP, sehingga tidak akan berfungsi.

Dari dokumentasi:

Gaya komentar "satu baris" hanya berkomentar di akhir baris atau blok kode PHP saat ini, mana yang lebih dulu. Ini berarti bahwa kode HTML setelah // ...?> Atau # ...?> AKAN dicetak:?> Keluar dari mode PHP dan kembali ke mode HTML, dan // atau # tidak dapat memengaruhi itu.

Anirudh Ramanathan
sumber
Terima kasih, banyak hal yang saya masih belum tahu ... Ini membantu.
v1n_vampire
4
Pos ini layak mendapatkan +1 lebih banyak ... Untuk penjelasan menyeluruhnya saja.
ppeterka
15

Gagasan lain: Kabur dari >(dan /, jika Anda ingin menggunakan /*...*/komentar):

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

Pelarian "yang tidak perlu" diabaikan oleh mesin regex, tetapi berguna dalam kasus ini (untuk alasan yang diuraikan dalam jawaban lain).

Tim Pietzcker
sumber
@ppeterka: Saya menggunakan backslash bukan kelas karakter (tapi ya, saya memang melewatkan satu kejadian. Terima kasih!)
Tim Pietzcker
Maaf, sepertinya saya lelah ... Saya perhatikan yang kedua, yang tersisa di sana dikelilingi oleh [] ...
ppeterka
10

Mengapa menggunakan "trik" yang rumit, sulit dibaca untuk menyelesaikan masalah?

? hanyalah pintasan kuantifier untuk kenyamanan, jadi

Cukup gunakan versi panjang quantifier{0,1} , berarti "minimum 0 maksimum 1 kejadian":

$string = preg_replace('#<br\s*/{0,1}>(?:\s*<br\s*/{0,1}>)+#i', '<br />', $string);
stema
sumber
1
+1 halaman ini mulai menjadi tempat yang sangat baik untuk mengumpulkan trik regex untuk diingat.
ppeterka
1
@ppeterka, saya sebenarnya akan menyebut semua jawaban lain "trik", tetapi jawaban saya hanya menggunakan versi panjang dari kuantifier dan bukan pintasan.
stema
3
Jangan tersinggung, hanya saja dalam kamus saya, menggunakan versi panjang dari ekspresi alih-alih yang lebih pendek, gula sintaksis yang dianggap sebagai trik juga ...
ppeterka
8

Beberapa cara lain yang layak ditambahkan ke buku trik RegEx :

Pertama, Anda bisa memadatkan RegEx Anda ke: /(<br\s*/?>)+/idan ganti dengan<br /> (tidak perlu membebani RegExP dengan lookaheads) dan Anda akan selalu berakhir dengan jeda baris XHMTL yang Anda pilih.

Cara lain untuk memodifikasi RegEx Anda sehingga tidak akan tersandung */komentar ?>akhir atau skrip akhir:

  • Gunakan quantifiers posesif : #(<br\s*+/?+>)+#i- yang pada dasarnya berarti \s*+jika Anda menemukan kecocokan spasi sebanyak yang ada dan simpan, dan karena /?+jika Anda menemukan garis miring, pertahankan!
  • Lampirkan \s*dan /*dalam kelompok tangkap =>#(<br(\s*)(/?)>)+#i

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

Dan karena kita bersandar pada perilaku posesif, RegEx tercepat yang juga mem-bypass masalah komentar adalah: menjelaskan demo#(<br\s*+/?+>)++#i


Adapun komentar dalam situasi sulit

Ketika Anda tidak dapat mengubah kode, atau sudah menggunakan komentar multiline dan:

1. Gunakan nowdoc :

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

Kode langsung: http://codepad.viper-7.com/22uOtV

Catatan: nowdoc mirip dengan heredoc tetapi tidak mem-parsing konten dan harus memiliki pembatas awal yang dilampirkan dalam 'tanda kutip tunggal '( perhatikan bahwa pembatas akhir tidak dapat diidentifikasi , harus diikuti oleh ;dan baris baru ! )

2. Melompati kode dengan goto :

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

Contoh langsung: http://codepad.viper-7.com/UfqrIQ

3. Melompati kode dengan if(false)atau if(0):

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

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

CSᵠ
sumber