Perl - Pętle
Instrukcja foreach.
Dzięki instrukcji foreach możemy przemieszczać się kolejno poprzez elementy tablicy lub kolejne linie pliku tekstowego i wykonywać na nich operacje. Dla przykładu wykorzystamy wcześniej już używaną tablicę @imiona:
foreach $imie (@imiona) # każdy kolejny # element tablicy # @imiona będzie # chwilowo dostępny # pod zmienną $imie { print "KTO : "; print "$imien"; }
Nawiasy klamrowe, jakie pojawiły się powyżej, są używane do określania bloku programu, czyli zbioru instrukcji i wyrażeń. W tym akuratnie przypadku za każdym podstawieniem pod zmienną $imie nowej wartości wykonywane są dwie czynności. Instrukcja foreach odnosi się do obydwu z nich.
Rozważymy teraz kilka wyrażeń testujących. Testy porównują ze sobą zmienne lub wartości i zwracają prawdę lub fałsz. W Perlu każda liczba różna od zera i każdy łańcuch, który nie jest pusty, jest uznawany za prawdę, zaś liczba 0 lub pusty łańcuch za fałsz. I tak:
$a == $b # prawda jeśli $a jest # liczbowo równe $b $a != $b # prawda jeśli $a jest # liczbowo różne od $b $a eq $b # prawda jeśli łańcuch # $a jest taki sam jak $b $a ne $b # prawda jeśli łańcuchy # $a i $b się różnią
A tak używamy logicznych wartości AND, OR, NOT:
($a && $b) # Czy $a i $b są prawdą? ($a || $b) # Czy $a lub $b jest prawdą? (!$a) # Czy $a to fałsz?
Przedstawione powyżej testy znajdują zastosowanie m.in. w budowaniu instrukcji warunkowych, których ogólna postać wygląda następująco:
if test1 { operacje1; } elsif test2 { operacje2; } else { operacje3; }
Instrukcje takie działają na następującej zasadzie: Jeśli okaże się, że test1 wykazuje wartość prawda, to zostaje wykonany pierwszy blok programu - operacje1. Jeśli test1 się nie powiedzie, to zostaje przeprowadzony test2 i, jeśli ten się powiedzie, wykonanywane są operacje2. (Jedna instrukcja warunkowa może zawierać wiele członów elsif). Następny, zaczynający się od słowa else człon instrukcji dotyczy przypadku, w którym żaden z wcześniejszych testów się nie powiódł. (W najprostszym razie człony elsif i else nie muszą się w ogóle pojawić).
Przykładowo ta instrukcja warunkowa sprawdzi, czy łańcuch $a jest pusty czy też zawiera jeden, dwa a może więcej znaków, a następnie wypisze odpowiedni komunikat:
if (!$a) # czy łańcuch $a # zwraca fałsz? { print "Łańcuch jest pusty.n"; } elsif (length($a) == 1) # czy łańcuch $a # ma jeden znak? { print "Łańcuch składa się"; print " z jednego znaku.n"; } elsif (length($a) == 2) # czy łańcuch $a # ma dwa znaki? { print "Łańcuch składa się"; print " z dwóch znaków.n"; } else # gdy ilość znaków > 2 { print "Łańcuch składa się"; print " z wielu znaków.n"; }
Za pomocą instrukcji unless możemy w jeszcze inny sposób sprawdzać prawdziwość testów i na tej podstawie wykonywać stosowne operacje. Możliwe są dwa, równoważne sposoby budowania instrukcji unless:
operacja unless test; unless test operacja;
Działanie tej instrukcji polega na tym, że operacja jest wykonywana, chyba że test zwraca wartość prawda. Przykładowo:
die unless ($l); # zakończ działanie # programu, jeżeli # zmienna $l jest pusta
Poznamy teraz zasadę budowania podstawowej, pochodzącej bezpośrednio z języka C pętli for. W ogólności pętla ta wygląda następująco:
for (inicjalizacja; test; zmiana_wartości) { operacje; }
Na początku pętli for wykonywana jest inicjalizacja. Następnie przeprowadzany jest test i jeśli zwróci on wartość prawda, zostają wykonane operacje. W ostatnim etapie ma miejsce zmiana_wartości, która najczęściej polega na zwiększeniu o jednostkę zmiennej ustalonej podczas inicjalizacji. (Zmiana_wartości jest wyrażeniem wykonywanym zawsze, w każdym przebiegu pętli). Cała pętla wykonywana jest dopóki test nie zwróci fałszu.
Oto przykład pętli for, która wypisze cyfry od 0 do 9:
for ($a = 0; $a < 10; ++$a) { print "$an"; }
Inny sposób zapętlania uzyskujemy dzięki instrukcji while. Ogólna jej konstrukcja przedstawia się następująco:
while test { operacje; } continue { operacje; }
Działanie jej polega na ciągłym wykonywaniu bloku operacji, jeśli tylko test zwraca prawdę. Drugi człon (począwszy od słowa continue) nie jest niezbędny, a jego rola jest taka sama jak elementu zmiana_wartości w pętli for - wyrażenie to jest wykonywane w każdym przebiegu pętli.
Oto przykład pętli while, która pyta użytkownika o wynik działania matematycznego i powtarza swoje pytanie, dopóki nie uzyska poprawnej odpowiedzi:
print 'Ile to jest 2*2, hmm? '; $a = <STDIN>; # tak czytamy dane ze # standardowego wejścia chop($a); # odcięcie znaku końca # linii while($a ne 4) # powtarzaj, dopóki # użytkownik nie poda # dobrego wyniku { print "Niestety to zły wynik!n"; print "Spróbuj ponownie: "; $a = <STDIN>; chop($a); } print "Jakoś Ci się udało.n";
W Perlu, podobnie jak w większości innych języków, istnieje instrukcja goto, pomimo że można ją w każdym przypadku z powodzeniem zastąpić pętlami. (Jej nadużywanie nie należy do kunsztu programistycznego). Postać instrukcji goto jest następująca:
operacje; znacznik: operacje; goto znacznik;
Instrukcja powoduje zatrzymanie programu i przeskok do punktu, w którym został umieszczony znacznik.
Poniższy program po uruchomieniu będzie wypisywał na ekranie dane słowo w nieskończoność:
re: # znacznik print " HEJ ! "; # dalszy ciąg programu goto re; # przeskok wstecz # do znacznika
W Perlu budowanie instrukcji jest dosyć dowolne. Ten sam efekt bardzo często możemy uzyskać na wiele sposobów, a wybranie jednego z nich zależy wyłącznie od własnych upodobań.
Oto przykładowy program obliczający sumę algebraiczną z podanych przez użytkownika liczb. Wykorzystuje on poznane wcześniej instrukcje:
do # tak też można { print "Proszę podać liczbę : "; $liczba = <STDIN>; $efekt += $liczba; ++$numer; } until ($liczba eq "n"); # dopóki użytkownik # przestanie # wprowadzać liczby if ($numer != 0) { $sr = $efekt / $numer; print "Średnia arytmetyczna podanych liczb:"; print " $srn"; }
Ten przykładowy program natomiast służy do odnajdywania liczb pierwszych według dość prymitywnego algorytmu:
print "Proszę podać liczbę : "; $l = <STDIN>; chop($l); for($i = 2; $i < $l; $i++) { if (($l % $i) == 0) { print "Liczba $l nie jest pierwsza!n"; exit; } } print "Liczba $l jest pierwsza!n";