tarafından Guido Socher
Yazar hakkında:
Guido eski tüfek bir Linux fanatiği ve Perl kırıcısıdır. Kendi görsel yöresini aşağıdaki linkte bulabilirsiniz.
www.oche.de/~bearix/g/.
İçerik:
|
Perl kısım III
Çeviri : Selahattin Dinç
Özet:
Perl kısım I size Perl hakkında genel bir fikir verecektir.
Perl'in kısım II'sinde ilk yardımcı program yazıldı. Kısım III'te ise dizilere daha yakından inceleyeceğiz.
Diziler
Bir dizi, kendisine bir indeks ile ulaşılabilen değişkenlerin bir listesini içerir.
Bilindiği gibi "normal değişkenler", aynı zamanda yönsüz(skaler) değişkenler olarak bilinir ve isimleri de dolar($) işaretiyle başlar.
@-işaretiyle başlayan dizilerde de dizi bir çok yönsüz değişken içerir.
Bundan dolayı dizi içinde özel alanlar belirttiğimizde dolar işaretini yazmayı unutmamalıyız.
Hep beraber şu örneğe bir göz atalım:
!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et:
# declare a new array variable:
my @myarray;
# initialize it with some data:
@myarray=("data1","data2","data3");
# access the first element (at index 0):
print "the first element of myarray is: $myarray[0]\n";
|
Gördüğünüz gibi herşeyden bahsettiğimizde @myarray yazdık ve özel bir elemntten bahsederken
$myarray[0] yazdık.
Perl dizileri index 0 dan başlarlar. Yeni indexler ise veri işaretlediğimiz an hemn oluşturulur. Bildirme zamanında dizinin büyüklüğünün ne kadar oalcağını bilmek zorunda değilsiniz.
Yukarıda gördüğünüz gibi bir veri demetini parantezlerin arkasına bir noktalıvirgül koyarak bir araya toplayabilirsiniz.
("data1","data2","data3")
gerçekten anonim bir dizidir.
Bundan dolayı bu anonim diziden ikinci elemanı almak için
("data1","data2","data3")[1]
yazabilirsiniz:
!/usr/bin/perl -w
print "The second element is:"
print ("data1","data2","data3")[1];
print "\n"
|
Diziler üzerinde döngü
Perl'de foreach döngüsü dizinin bütün elemanları üzerinde bir döngü kurmayı
olanaklı kılar.
Bu aşağıdaki gibi çalışır:
#!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et:
my @myarray =("data1","data2","data3");
my $lvar;
my $i=0;
foreach $lvar (@myarray){
print "element number $i is $lvar\n";
$i++;
}
|
Bu program çalıştırıldığında şu sonucu verir:
element number 0 is data1
element number 1 is data2
element number 2 is data3
|
foreach ifadesi diziden her bir elemanı alıp döngü değişkenine sokar(yukarda örnekteki $lvar gibi)
Şunu önemle belirtmek gerekir ki değerler diziden kopyalanmak suretiyle döngünün içine sokulmuyorlar.
Döngü değişkeni yerine bazı işaretçi ve döngü değişkenlerinin değiştirilmesi dizinin içindeki elemanları değiştirir.
Aşağıdaki program dizinin içindeki bütün elemanları büyük harf yapar.
Perl deki
tr/a-z/A-Z/ Unix'teki "tr" komutuna benzer. Bahsedilen koşullarda bütün harfleri büyük harfe çevirir.
#!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et:
my @myarray =("data1","data2","data3");
my $lvar;
print "before:\n";
foreach $lvar (@myarray){
print "$lvar\n";
$lvar=~tr/a-z/A-Z/;
}
print "\nafter:\n";
foreach $lvar (@myarray){
print "$lvar\n";
}
|
Programı çalıştırdığınız zaman göreceksiniz ki sadece @myarray içeren ikinci döngü değişkenleri büyük harf yapacaktır:
before:
data1
data2
data3
after:
DATA1
DATA2
DATA3
|
Komut satırı
Perl II'de görüldüğü üzere bir &getopt fonksiyonu komut satırını okumada ve komut satırıyla
gerçekleştirilebilen herhangi bir seçeneği kullanmada kullanılabilir.
&getopt fonksiyonu C'dekiyle aynıdır. Bu bir kitaplık fonksiyonudur.
Komut satırından değişken almak için Perl'de kullanılan dizi @ARGV olarak isimlendirilmiştir.
&getopt fonksiyonu sadece bu @ARGV yi alır ve elemanları değerlendirir.
C'dekinden farklı olarak programın ismi dizideki ilk elemanın içeriği değil
komut satırının ilk elemanı program ismidir.
Eğer perl programının ismini öğrenmek istiyorsanız $0'ı okumak zorundasınız.
Makalemizin konusu
bu olmadığı için şimdilik buna değinmeyeceğiz.
Bu da
add adlı örnek
programımız.
Bu program komut satırından iki rakam alır ve bunları toplar:
.... ve bu da programımız:
#!/usr/bin/perl -w
# check if we have 2 arguments:
die "USAGE: add number1 number2\n" unless ($ARGV[1]);
print "$ARGV[0] + $ARGV[1] is:", $ARGV[0] + $ARGV[1] ,"\n";
|
Bir Yığıt
Perl'de bir diziyi yığıt olarak kullanan kendinden menkul bir dizi fonksiyon
vardır.
- push bir elemanı dizinin sonuna ekler.
- pop bir elemanı dizinin sonundan okumaya yarar.
- shift dizinin başından bir elemanı okumaya yarar.
- unshift dizinin başlangıcına bir eleman eklemeye yarar.
Bir sonraki program
mevcut bir diziye iki eleman ekler:
#!/usr/bin/perl -w
my @myarray =("data1","data2","data3");
my $lvar;
print "the array:\n";
foreach $lvar (@myarray){
print "$lvar\n";
}
push(@myarray,"a");
push(@myarray,"b");
print "\nafter adding \"a\" and \"b\":\n";
while (@myarray){
print pop(@myarray),"\n";
}
|
Pop, dizinin sonundaki elemanı çıkarır ve dizi boşalana kadar while döngüsü çalışır.
Dizin Okuma
Perl'ün bir dizinin içeriğini okumak için bize sunduğu fonksiyonlar;
opendir, readdir fonksiyonlarıdır.
readdir, bir diziye bütün dosya isimleriyle döner.
foreach döngüsünü kullanarak bütün dosya isimlerini döndüre bilir ve bir isim vererek arama yapabilirsiniz.
Bu örnek program içinde bulunulan
dizinde verilen dosya ismini arar.
#!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et:
die "Usage: search_in_curr_dir filename\n" unless($ARGV[0]);
opendir(DIRHANDLE,".")||die "ERROR: can not read current directory\n";
foreach (readdir(DIRHANDLE)){
print"\n";
print "found $_\n" if (/$ARGV[0]/io);
}
closedir DIRHANDLE;
|
Şimdi programa bir bakalım. İlk önce kullanıcının komut satırı argumanını sağlayıp sağlamadığını
kontrol ettik. Eğer sağlanmamışsa kullanım bilgisini ekrana bastırdık ve çıktık.
Sonra içinde bulunduğumuz dizini açtık ("."). opendir fonksiyonu,
dosyalar için geçerli olan
the open functionsile aynıdır.
İlk argüman readdir ve closedir fonksiyonlarını geçmek için gerekli olan
dosya tanımlayıcısıdır.
İkinci argüman dizine açılan patikadır.
Sonraki foreach döngüsüne gelir.
İlk ilgiçekici durum döngü değişkeninin atlanmasıdır.
Perl bu durumda sizin için sihirli bir formül geliştirir ve $_ adında bir değişken oluşturur.
Bu değişken de döngü değişkeni olarak kullanılır.
readdir(DIRHANDLE) fonksiyonu bir diziye döner ve biz de her elemana bakmak için foreach döngüsü kullanılır.
/$ARGV[0]/io ise $ARGV[0] içindeki sıradan ifadeyi $_ değişkenine ile eşleştirilir(karşılaştırılır).
Burdaki io ise aramayı büyük küçük harf eşleştirmesiz yapmasını ve sıradan ifadeyi sadece bir kere derlemesini ifade eder.
Bir sonraki ise programı daha hızlı hale getiren bir iyileştirmedir.
Sıradan ifadenin içinde bir değişkeniniz olduğu zaman bunu kullanabilirsiniz ve emin olabilirsiniz ki değişken çalıştırma anında değişmez.
Şimdi bir deneyelim. Varsayalım ki içinde bulunduğumuz dizinde article.html, array1.txt ve array2.txt adında dosyalar olsun. Sonra "HTML" ile arattığımızda şu sonuç verilecektir.
>search_in_curr_dir HTML
.
..
article.html
found article.html
array1.txt
array2.txt
Gördüğünüz gibi readdir fonksiyonu 2 tane fazladan dosya buldu. "." ve
"..". Bunlar içinde bulunulan ve bir önceki dizinlerin isimleri.
Bir dosya bulucusu
Bu makaleyi biraz karmaşık ve daha kullanışlı bir örnekle bitirmek istiyorum.
Bu bir dosya bulma programı olacak. Programımızın adını pff((perl file
finder) perl dosya bulucusu) koyalım.
Bu temel olarak yukardaki program gibi çalışacak fakat farklı olarak al dizinlerde de arama yapabilecek.
Peki böyle bir programı nasıl yapacağız? Yukarda içinde bulunulan dizinde arama yapan bazı kodalarımız vardı.
İçinde bulunduğumuz dizinden başlamamız gerekir fakat (. ve .. dışında) eğer içinde bulunduğumuz dizinin içinde başka dizinler de varsa bunların içinde de arama yapmak gerekir.
Bu tipik bir yinelemeli algoritmadır.
sub search_file_in_dir(){
my $dir=shift;
...read the directory $dir ....
...if a file is again a directory
then call &search_file_in_dir(that file)....
}
if (-d "$file" && ! -l "$dir/$_"){....} yapısını kullanarak bir dosyanın dizin mi yoksa bir symlink mi olduğunu anlayabilirsiniz.
Şimdi programı yazabilmek için gereken bütün codlarımızı alalım.
the actual code (pff.gz).
#!/usr/bin/perl -w
# vim: set sw=8 ts=8 si et:
# written by: guido socher, copyright: GPL
#
&help unless($ARGV[0]);
&help if ($ARGV[0] eq "-h");
# start in current directory:
search_file_in_dir(".");
#-----------------------
sub help{
print "pff -- perl regexp file finder
USAGE: pff [-h] regexp
pff searches the current directory and all sub-directories
for files that match a given regular expression.
The search is always case insensitive.
EXAMPLE:
search a file that contains the string foo:
pff foo
search a file that ends in .html:
pff \'\\.html\'
search a file that starts with the letter \"a\":
pff \'^a\'
search a file with the name article<something>html:
pff \'article.*html\'
note the .* instead of just *
\n";
exit(0);
}
#-----------------------
sub search_file_in_dir(){
my $dir=shift;
my @flist;
if (opendir(DIRH,"$dir")){
@flist=readdir(DIRH);
closedir DIRH;
foreach (@flist){
# ignore . and .. :
next if ($_ eq "." || $_ eq "..");
if (/$ARGV[0]/io){
print "$dir/$_\n";
}
search_file_in_dir("$dir/$_") if (-d "$dir/$_" && ! -l "$dir/$_");
}
}else{
print "ERROR: can not read directory $dir\n";
}
}
#-----------------------
|
Şimdi birazcık programı inceleyelim. İlk önce kullanıcının komut satırına geçerli komutu girip girmediğini test ettik. Eğer değilse bir hata mesajı çıkartıp küçük bir yardım yazısı çıkaracağız. Ayrıca -h seçeneği verilirse ayrı bir yardım metni göstereceğiz.
Aksi durumda içinde bulunduğumuz dizinden itibaren aramaya başlarız.
Yukarda tanımlanan yinelemeli(recursive) algoritmayı kullanırız.
Dizini oku, dosyaları ara, dosyanın bir dizin olup olmadığını test et, eğer olumlu ise(dizin ise) search_file_in_dir() fonkisoyunu tekrar çağır.
İfadenin içinde, dizinleri kontrol ettiğimiz yerde aynı zamanda dizinin başka bir dizine link olmadığını da kontrol etmiş oluruz.
Bunu kontrol etmemiz gerekir çünkü belki birisi ".." dizinine sym-lınk oluşturmuştur.
Böyle bir kontrol yapılmadığı takdirde program sonsuz döngüye girecektir.
next if ($_ eq "." || $_ eq ".."); ise henüz üzerinde konuşmadığımız bir ifadedir.
"eq" operator ise Perl'deki katar karşılaştırma operatörüdür.
Burda ise $_ değişkeninin içeriğini ".." veya "." eşit olup olmadığını anlamak için test ettik.
Eğer bu eşitse "next" ifadesi çalıştırıldı.
Bir foreach döngüsü içindeki "next" ifadesi döngünün en başına dönülüp dizinin ikinci elemanı ile döngüye devam edilmesi anlamına gelir.
Bu C'deki "continue" durumuna benzer.
Kaynaklar
Aşağıda Perl hakkında yazılmış bazı ilginç yazıların bir listesini veriyoruz.
Bu yazı için görüş bildiriminde bulunabilirsiniz
Her yazı kendi görüş bildirim sayfasına sahiptir. Bu sayfaya yorumlarınızı yazabilir ve diğer okuyucuların yorumlarına bakabilirsiniz.
2001-03-09, generated by lfparser version 2.9