Konwertuj tag zamykający PHP na komentarz

149

Jedna z linii mojego skryptu zawiera tag zamykający PHP wewnątrz ciągu. Podczas normalnej pracy nie powoduje to problemu, ale muszę zakomentować linię.

Próbowałem skomentować tę linię //, /* */a #jednak żaden z nich nie działa, parser rozważa zamknięcie tag być rzeczywisty znacznik zamykający.

Oto omawiany wiersz:

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

Co mogę zrobić, aby zakomentować powyższą linię?

v1n_vampire
źródło
18
Zabawny problem, ale prawdziwy. Głosuję za.
Voitcus
17
O MÓJ BOŻE. Na początku byłem sceptyczny wobec twojego pytania, gotowy zapytać, w czym jest problem, ale potem próbowałem skomentować wiersz z ciągiem zawierającym „?>” I otrzymałem go. To powinno zostać dodane do długiej listy phpsadness.com
lolesque
6
Przydatność takiej „funkcji” jest wyjaśniona w php.net/manual/en/language.basic-syntax.comments.php , jest przydatna w przypadku jednowierszowego<?php # echo 'simple';?> .
lolesque
2
@lolesque Dzięki za ten link. Dobry. Powiązany, który obejmuje również inne języki: wiki.theory.org/YourLanguageSucks
Simon Forsberg
5
@ OndraŽižka wszystko, co robi, to usuwanie powtarzających się tagów br. w tym przypadku wyrażenie regularne działa dobrze. To, że czasami jest złe, nie oznacza, że ​​jest złe przez cały czas.
Kip

Odpowiedzi:

124

Użyj sztuczki: połącz strunę z dwóch kawałków. W ten sposób tag zamykający jest przecinany na pół i nie jest już prawidłowym tagiem zamykającym.'?>' --> '?'.'>'

W swoim kodzie:

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

Dzięki temu //komentarze będą działać.

Aby /* */komentarze działały, musiałbyś również podzielić */sekwencję:

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

Pamiętaj, czasami, mimo że całość to coś więcej niż suma jej części - ale bycie chciwym jest złe, są chwile, gdy lepiej zostawić ci mniej . :)

ppeterka
źródło
@ppeterka Wow, nawet o tym nie myślałem. Dziękuję Ci.
v1n_vampire
1
Musiałem użyć tej sztuczki w C 2 dni temu dla stringa zawierającego??<
Ryan Amos
2
Świetny. Dlaczego nigdy nie myślę w ten sposób !?
San
73

Najłatwiejszy sposób

Utwórz oddzielną zmienną do przechowywania wyrażenia regularnego; w ten sposób możesz po prostu skomentować preg_replace()oświadczenie:

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

Napraw za pomocą klas postaci

Aby naprawić komentarze do linii, możesz przerwać, ?>umieszczając >wewnątrz klasy znaków, jak na przykład:

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

Aby naprawić komentarze blokowe, możesz zastosować je do /:

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

Aby naprawić oba style komentarzy, możesz wstawić / i > do ich własnej klasy znaków.

Napraw za pomocą /xmodyfikatora

x Modyfikator - aka PCRE_EXTENDED- ignoruje spacje i znaki nowej linii w wyrażeniach regularnych (z wyjątkiem, gdy występują one w środku klasy postaci); umożliwia to dodanie spacji w celu oddzielenia problematycznych znaków. Aby naprawić oba style komentarzy:

$string = preg_replace('#<br\s* /? >(?:\s*<br\s* /? >)+#ix', '<br />', $string);
                               ^  ^             ^  ^
Jacek
źródło
@Cthulhu +1 (i oczywiście za odpowiedź). Ponadto (przynajmniej dla mnie) sprawia to, że wyrażenie regularne jest nieco trudniejsze do zrozumienia. Niewiele, ale gdybym zobaczył to wyrażenie regularne, powiedziałbym: Hmmm, co się dzieje? Ale to jest oczywiste i całkowicie subiektywne.
ppeterka
1
@ppeterka Raczej się zgadzam, więc znalazłem inny sposób, używając xmodyfikatora :)
Ja͢ck
@Jack Nice, dałbym za to kolejne +1, nauczyłem się czegoś nowego ... Ciągle zapominam o modyfikatorach regex (rzadko ich używam poza g) ...
ppeterka
@Jack Dziękuję, z rozwiązania dowiaduję się nowych rzeczy o wyrażeniu regularnym.
v1n_vampire
1
+1 za oddzielenie wyrażenia regularnego do wcześniejszej linii. Zachowuje to samo wyrażenie regularne, ale nadal umożliwia wykomentowanie logiki.
38

Dlaczego twoje próby się nie powiodły:

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

Co działa:

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

Dalej...

Po powyższym powinieneś móc użyć /*do zakomentowania linii. Jeśli zostawisz to ?>nietknięte, //nie możesz wykomentować całej linii. Poniższy tekst ?>może być html, który jest poza kontrolą interpretera PHP, więc to nie zadziała.

Z dokumentacji:

Style komentarzy „jednowierszowe” komentują tylko do końca wiersza lub bieżącego bloku kodu PHP, w zależności od tego, co nastąpi wcześniej. Oznacza to, że kod HTML po // ...?> Lub # ...?> BĘDZIE drukowany:?> Wychodzi z trybu PHP i powraca do trybu HTML, a // lub # nie mogą na to wpłynąć.

Anirudh Ramanathan
źródło
Dziękuję, tyle rzeczy, których nadal nie wiem ... To pomocne.
v1n_vampire
4
Ten post zasługiwałby na znacznie więcej + 1-ek ... Tylko za dokładne wyjaśnienie.
ppeterka
15

Inny pomysł: Escape the >(i /, jeśli chcesz użyć /*...*/komentarza):

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

Silnik wyrażeń regularnych ignoruje „niepotrzebne” zmiany znaczenia, ale jest w tym przypadku przydatne (z powodów przedstawionych w innych odpowiedziach).

Tim Pietzcker
źródło
@ppeterka: Użyłem odwrotnego ukośnika zamiast klasy znaków (ale tak, przegapiłem jedno wystąpienie. Dzięki!)
Tim Pietzcker
Przepraszam, wygląda na to, że jestem zmęczony ... Zauważyłem drugą, która została tam otoczona [] ...
ppeterka
10

Po co używać skomplikowanych, trudnych do odczytania „sztuczek”, aby obejść problem?

? jest tylko wygodnym skrótem do kwantyfikatora, więc

Po prostu użyj długiej wersji kwantyfikatora{0,1} , czyli „minimum 0, maksimum 1 wystąpienie”:

$string = preg_replace('#<br\s*/{0,1}>(?:\s*<br\s*/{0,1}>)+#i', '<br />', $string);
stema
źródło
1
+1 ta strona zaczyna być bardzo dobrym miejscem do zbierania sztuczek regex, które warto zachować w tyle.
ppeterka,
1
@ppeterka, właściwie nazwałbym wszystkie inne odpowiedzi „sztuczkami”, ale moja odpowiedź to po prostu użycie długiej wersji kwantyfikatora, a nie skrótu.
stema
3
Bez urazy, tylko że w moim słowniku, używając dłuższej wersji wyrażenia zamiast krótszego, wygodniejszego cukru syntaktycznego, liczy się też jako podstęp ...
ppeterka
8

Kilka innych sposobów, które warto dodać do książki trików RegEx :

Najpierw możesz skompaktować wyrażenie regularne do: /(<br\s*/?>)+/ii zamienić na<br /> wyrażenie regularne (nie ma potrzeby obciążania wyrażenia regularnego z wyprzedzeniem), a zawsze otrzymasz wybrany podział wiersza XHMTL.

Inne sposoby modyfikowania wyrażenia regularnego, aby nie wyłączało */komentarza lub ?>skryptu:

  • Użyj kwantyfikatorów dzierżawczych : #(<br\s*+/?+>)+#i- co w zasadzie oznacza, że \s*+jeśli znalazłeś tyle białych znaków, ile jest i zachowasz je, a /?+jeśli znalazłeś ukośnik, zachowaj go!
  • Zamknięcie \s*i /*w grupach przechwytywania =>#(<br(\s*)(/?)>)+#i

Dema na żywo: http://codepad.viper-7.com/YjqUbi

A ponieważ oparliśmy się na zachowaniu zaborczym, najszybszym wyrażeniem regularnym, które również omija problem komentowania, jest: wyjaśnione demo#(<br\s*+/?+>)++#i


Co do komentowania w trudnych sytuacjach

Kiedy nie możesz zmienić kodu lub użyłeś już komentarza wielowierszowego i:

1. Skorzystaj z nowdoc :

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

Kod na żywo: http://codepad.viper-7.com/22uOtV

Uwaga: nowdoc jest podobny do heredoc, ale nie analizuje treści i musi mieć swój początkowy ogranicznik ujęty w 'pojedyncze cudzysłowy '( pamiętaj, że ogranicznika końcowego nie można zidentyfikować , musi po nim następować ;i nowa linia ! )

2. Przeskocz kod za pomocą goto :

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

Przykład na żywo: http://codepad.viper-7.com/UfqrIQ

3. Przeskocz nad kodem za pomocą if(false)lub 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ᵠ
źródło