2008-10-08 14 views
11

Czy istnieje sposób, aby to zrobić w jednym wierszu?Czy istnieje wyrażenie regularne zgodne z Perl, aby przyciąć białe znaki z obu stron napisu?

$x =~ s/^\s+//; 
$x =~ s/\s+$//; 

Innymi słowy, usuń wszystkie początkowe i końcowe białe spacje z ciągu znaków.

+2

"Wykończenie" to normalna nazwa usuwania białego trójkąta z obu stron napisu. możesz: $ title = ~ s/remove/trim/ – Kip

+0

Usuwam znacznik "pcre", ponieważ jest to nazwa biblioteki regex C (tej, która obsługuje funkcje preg PHP), a to oczywiście nie jest to, jak jest używana tutaj. –

Odpowiedz

26
$x =~ s/^\s+|\s+$//g; 

lub

s/^\s+//, s/\s+$// for $x; 
+0

Opcja 2: To fajna sztuczka, ale tak naprawdę nie odpowiada na pytanie: D – ephemient

+2

Jak to nie odpowiada na pytanie? Jest przycinanie z obu stron bez wydajności ssania naprzemiennego pojedynczego regex. –

+0

s/^ \ s * (. *?) \ S */\ 1 /; musi wypróbować więcej alternatyw niż jedna z tych dwóch opcji. –

4

Proszę bardzo: $x =~ s/\A\s*(.*?)\s*\z/$1/;

2

$ x = ~ s/(^ \ s +) | (\ s + $) // g;

+1

tak to zawsze robię .. wydaje się zdecydowanie najłatwiejszy. – Kip

+0

tak, i mówi, co to znaczy - zastępuje początkową białą przestrzeń LUB kończy białą przestrzeń nic, globalnie. –

+2

Parens przechwytywania nie są używane lub potrzebne - na ogół można je zastąpić parens grupowania (?: ...), ale w tym przypadku pierwszeństwo działa ładnie i można całkowicie usunąć nawiasy. – ephemient

-2
$x =~ s/^\s*(.*?)\s*$/$1/; 
+0

Używanie \ 1 zamiast $ 1 w ciągu zastępującym jest odradzane w Perlu, patrz "Ostrzeżenie o \ 1 wobec $ 1" w 'perldoc perlre'. – ephemient

+0

Ponieważ kwantyfikatory są chciwe, nie musisz mówić czegoś takiego jak [^ \ s] po dopasowaniu \ s +. Ponadto, zamiast [^ \ s], możesz po prostu powiedzieć \ S. Wersje wielkiej litery są uzupełnionymi klasami znaków. :) –

+0

brian: Tak, ale tylko jeśli zrobię. * Nieużytkiem. – Lev

0
s/^\s*(\S*\S)\s*$/$1/ 
+0

Używanie \ 1 zamiast $ 1 w ciągu zastępującym jest odradzane w Perlu, patrz "Ostrzeżenie przy \ 1 do $ 1" w 'perldoc perlre'. – ephemient

+0

Masz rację, poprawię to. –

+0

Problem polega na tym, że potrzebujesz co najmniej dwóch nie białych znaków w łańcuchu lub nie będzie działać. – bart

30

Moje pierwsze pytanie brzmi ... dlaczego? Nie widzę żadnego z rozwiązań pojedynczego regexp, które byłyby bardziej czytelne niż regexp, z którego zacząłeś. I na pewno nie są tak blisko.

#!/usr/bin/perl 

use strict; 
use warnings; 

use Benchmark qw(:all); 

my $a = 'a' x 1_000; 

my @x = (
     " $a ", 
     "$a ", 
     $a, 
     " $a" 
     ); 

cmpthese(-5, 
     { 
      single => sub { 
       for my $s (@x) 
       { 
        my $x = $s; 
        $x =~ s/^\s+|\s+$//g; 
       } 
      }, 
      double => sub { 
       for my $s (@x) 
       { 
        my $x = $s; 
        $x =~ s/^\s+//; 
        $x =~ s/\s+$//; 
       } 
      }, 
      trick => sub { 
       for my $s (@x) 
       { 
        my $x = $s; 
        s/^\s+//, s/\s+$// for $x; 
       } 
      }, 
      capture => sub { 
       for my $s (@x) 
       { 
        my $x = $s; 
        $x =~ s/\A\s*(.*?)\s*\z/$1/ 
       } 
      }, 
      kramercap => sub { 
       for my $s (@x) 
       { 
        my $x = $s; 
        ($x) = $x =~ /^\s*(.*?)\s*$/ 
       } 
      }, 
     } 
     ); 

daje wyniki na mojej maszynie:

 
      Rate single capture kramercap  trick double 
single  2541/s  --  -12%  -13%  -96%  -96% 
capture 2902/s  14%  --  -0%  -95%  -96% 
kramercap 2911/s  15%  0%  --  -95%  -96% 
trick  60381/s  2276%  1981%  1974%  --  -7% 
double 65162/s  2464%  2145%  2138%  8%  -- 

Edit: Runrig jest w porządku, ale na niewiele się zmieniło. Zaktualizowałem kod, aby skopiować ciąg przed modyfikacją, co oczywiście spowalnia działanie. Uwzględniłem też sugestię Briana d Foy'a w innej odpowiedzi na użycie dłuższego łańcucha (choć milion wydawał się przesadą). Sugeruje to jednak, że zanim wybierzesz styl sztuczki, zorientujesz się, jakie są długości twoich ciągów - zalety trick są zmniejszane za pomocą krótszych łańcuchów. Na wszystkich długościach testowałem jednak podwójne wygrane. I wciąż jest łatwiej w oczach.

+0

Zakładasz, że robi to w Perlu, a to może nie być prawda. "Kompatybilny z Perl" zawsze podnosi dla mnie czerwoną flagę. –

+0

Prawda - to trochę zagmatwane, aby zobaczyć zarówno znaczniki perl, jak i pcre ... – Tanktalus

+0

Wszystkie twoje "testy" zostaną zmienione @x podczas pierwszej iteracji. Więc nikt nie testuje tego, co myślisz. Musisz skopiować @x w swoich subsach. W podwójnym rozwiązaniu nie owijaj go pętlą for, wystarczy użyć "dla @x". – runrig

5

Argumentując z herezją, dlaczego je w ogóle? Wszystkie powyższe rozwiązania są „poprawne” w tym, że przyciąć spacje po obu stronach napisu w jednym przejściu, ale nie są zbyt czytelne (a może oczekiwać this one). Jeśli publiczność twojego kodu nie składa się z koderów Perla na poziomie eksperta, każdy z powyższych kandydatów powinien mieć komentarz opisujący to, co robią (prawdopodobnie i tak dobry pomysł). Natomiast te dwie linie osiągnąć to samo bez użycia lookaheads, symbole wieloznaczne, midichlorines ani niczego, co nie jest od razu oczywiste dla programisty umiarkowanego Doświadczenie:

$string =~ s/^\s+//; 
$string =~ s/\s+$//; 

Jest (prawdopodobnie) hitem wydajności, ale jako o ile nie chodzi ci o kilka mikrosekund przy wykonaniu, wartość dodana będzie warta tego. MOIM ZDANIEM.

+0

Uderzenie wydajności? Kto mógłby się tak spierać? Jest ponad dwa razy szybszy niż jakiekolwiek inne rozwiązanie wymienione. – Tanktalus

+0

Niewystarczająco uczciwie, nie testowałem kodu, ponieważ chciałem wydostać się z drzwi (bardzo) późnego obiadu. Cieszę się, że nie ma żadnego uderzenia wydajności. – Logan

+0

Ekspert Perl? Ludzie w moim kursie Learning Perl zrozumieją wszystkie te rozwiązania do końca drugiego dnia. –

8

Tanktalus przedstawia wzorzec dla bardzo małych strun, ale problemy gorzej jak struny stają się coraz większe.W swoim kodzie, zmieniłem górną część:

my $a = 'a' x 1_000_000; 

my @x = (
    " $a ", 
    "$a ", 
    $a, 
    " $a" 
); 

mogę uzyskać te wyniki:

  Rate single capture trick double 
single 2.09/s  -- -12% -98% -98% 
capture 2.37/s  13%  -- -98% -98% 
trick 96.0/s 4491% 3948%  --  -0% 
double 96.4/s 4512% 3967%  0%  -- 

jako łańcuch robi się coraz większy, używając „trick” i „podwójne” są prawie takie same, a powszechne rozwiązanie, do którego dąży większość ludzi, "singiel" (w tym ja, ponieważ nie mogę złamać tego nawyku, mimo że to wiem), naprawdę zaczyna ssać.

Ilekroć patrzysz na wskaźnik, pomyśl o tym, co mówi. Aby sprawdzić, czy je rozumiesz, zmień dane i spróbuj ponownie. Uczyń tablice długimi, skalarami dużymi i tak dalej. Utwórz pętle, greps lub wyrażenia regularne znajdź rzeczy na początku, środku i końcu. Sprawdź, czy nowe wyniki pasują do Twojej prognozy. Dowiedz się, jaki jest trend. Czy wydajność jest coraz lepsza, zbliża się do limitu, szczyt zaczyna spadać, czy coś innego?

1

zwykle zrobić to tak:

($foo) = $foo =~ /^\s*(.*?)\s*$/; 

Wszystko między czołowych miejsc i spacje są pogrupowane i wrócił, więc mogę przypisać ją do tej samej zmiennej starego.

-1
$var1 =~ s/(^\s*)(.*?)(\s*$)+/$2/; 
Powiązane problemy