2011-07-08 12 views
6

Używam następujące policzyć liczbę wystąpień wzorca w pliku:Jak zignorować wszelkie puste wartości w perlu grep?

my @lines = grep /$text/, <$fp>; 
print ($#lines + 1); 

Ale czasami drukuje jeden więcej niż rzeczywista wartość. Sprawdziłem i to dlatego, że ostatni element @lines ma wartość null, a także jest zliczany.

W jaki sposób ostatni element wyniku grep może być pusty? W jaki sposób można rozwiązać ten problem?

+0

dlaczego dodajesz 1 do '$ # lines'? – sergio

+3

Nie wiedząc, jaki jest wzór, nie mamy wiele okazji do zrozumienia, dlaczego pasuje on do "pustej" linii. Należy jednak pamiętać, że linie kończą się \ n, co jest liczone jako coś do dopasowania. I w rzeczywistości niektóre wzory mogą w ogóle nie pasować do niczego. – DavidO

+0

@sergio, ponieważ '$ # lines' podaje indeks ostatniego elementu tablicy (który jest długością - 1 od 0) – Lazer

Odpowiedz

6

To bardzo zależy od twojego wzoru, ale jedną rzeczą, którą możesz zrobić, jest dołączenie do paru meczów, z których pierwszy dyskwalifikuje linię zawierającą tylko spację (lub nic). W tym przykładzie odrzucona zostanie tylko linia pusta, nowa linia lub dowolna ilość białych znaków.

my @lines = grep { not /^\s*$/ and /$test/ } <$fp>; 

Należy pamiętać, że jeśli zawartość $ testu stało się to wyrażenie regularne specjalne metaznaki one albo muszą być przeznaczone do ich celów Metaznak lub sterylizowane quotemeta().

Moje teorie sugerują, że linia może być zakończona w \ n, co w jakiś sposób pasuje do wyrażenia tekstowego $ text, lub wyrażenie tekstowe $ zawiera metaznaki, które wpływają na dopasowanie, bez wiedzy użytkownika. Tak czy inaczej, podany przeze mnie fragment będzie przynajmniej wymuszał odrzucenie "pustych linii", gdzie puste może oznaczać całkowicie puste (mało prawdopodobne), znak nowej linii zakończony, ale poza tym pusty (prawdopodobnie) lub białe znaki zawierające (możliwe) linie, które są puste po wydrukowaniu.

2

Wyrażenie regularne pasujące do pustego ciągu będzie zgodne z undef. Perl ostrzega przed zrobieniem tego, ale rzuca undef do '' przed próbą dopasowania przeciwko niemu, w którym to momencie grep będzie z radością promować undef do swoich wyników. Jeśli nie chcesz odebrać pustego ciągu (lub czegoś, co zostanie dopasowane tak, jakby był pustym łańcuchem), musisz przepisać swoje wyrażenie regularne, aby go nie pasowało.

+0

, ale kontekst listy '<>' nie powinien nigdy zwracać undef. – ysth

+0

To dobra uwaga. Co oznacza, że ​​spieprzyłem na kilka sposobów. Chciałbym, żeby Lazer wrócił i wyjaśnił, co znaczy "zerowy". – darch

+0

Podejrzewam, że tak naprawdę nie wie, co zawiera jego zmienna, dlatego moją odpowiedzią było jej sprawdzenie :) – ysth

2

Aby dokładnie zobaczyć, co jest w liniach zrobić:

use Data::Dumper; 
$Data::Dumper::Useqq = 1; 
print Dumper \@lines; 
+0

Istnieje stary moduł, który nigdy się nie starzeje. Aby debugować i ogólnie owijać się głowami wokół struktur danych, Data :: Dumper jest narzędziem pierwszej linii. Zaledwie kilka dni temu jego zdolność do zapewnienia widoczności w białych przestrzeniach zaoszczędziła mi trochę czasu. – DavidO

0

Ok, ponieważ nie więcej informacji o treści $text (regex) jest w przygotowaniu, chyba będę rzucać się ogólne informacje.

Rozważmy następujący przykład:

use Data::Dumper; 

my @array = (' ', 1, 2, 'a', ''); 
print Dumper [ grep /\s*/, @array ]; 

otrzymujemy:

$VAR1 = [ 
      ' ', 
      1, 
      2, 
      'a', 
      '' 
     ]; 

cały mecz wartości. Czemu? Ponieważ również pasują do pustego ciągu. Aby uzyskać to, czego chcemy, potrzebujemy \s lub . (Nie będzie praktycznej różnicy między tymi dwoma)

Możesz mieć taki problem.

Powiązane problemy