Bambang Nurcahyo Prastowo
Secara umum, urusan perkomputeran terdiri dari dua bagian: data dan program. Data adalah bagian yang diolah, sedangkan program adalah bagian instruksi pengolahannya.
Perl adalah salah satu program yang khusus dirancang untuk manipulasi teks seperti menyusun laporan rekapitulasi dari data-data transaksi dan sebagainya.
Perl menyediakan perintah kontrol yang umumnya tersedia di C.
Bab ini mengenalkan beberapa aspek pemrograman Perl secara singkat tetapi cukup lengkap untuk membantu pembaca menulis program yang relatif canggih.
Ada 3 bentuk struktur data di Perl: skalar, larik, dan asosiasi.
Skalar adalah data teks tunggal. Contoh: "padi", "kaca", "kacang atom", "1995", "18 Juni 1995", dsb. Jika teks skalar itu dapat dibaca sebagai angka, misalnya "15", "4.5", maka dia bisa diperlakukan sebagai angka. Mosalnya perkalian "15" * "3" menghasilkan skalar "45". Perhatikan, "15" * "3" tidak sama dengan "15 * 3". Skalar "15 * 3" adalah teks biasa yang berisi angka, spasi dan simbol * yang secara keseluruhan tidak bisa diperlakukan sebagai angka.
Larik adalah deretan skalar-skalar yang dipisahkan koma dan ditulis dalam tanda kurung. Contoh: ("padi", "jagung", "ubi"), ("senin", "selasa"), ("buku", "5", "pensil", "7"), dan sebagainya.
1.4. Asosiasi
Asosiasi adalah pasangan-pasangan dua skalar yang dipisahkan dengan koma dan ditulis dalam tanda kurung kurawal. Dua skalar dari tiap pasangan dipisahkan dengan tanda =>. Contoh:
"Bambang" =>"Kingston, Kanada", "Sumedi" => "USA", "Dwi" => "Osaka, Jepang")
Untuk mengetahui hasil pemrograman, diperlukan cara menampilkan data. Perl menyediakan perintah print untuk menampilkan data. Cara paling mudah menjalankan program perl adalah dengan menuliskannya di berkas, misalnya coba.pl, terus jalan kan dengan perintah (dos atau unix)
perl coba.pl
Contoh:
print "halo apakabar?"
akan menapilkan skalar "Halo apakabar?". Kalau lebih dari satu baris, perintah-perintah perl harus dipisahkan dengan semikolon ;.
Pertama, kita perlu bisa merujuk data. Data dirujuk dengan nama (atau tenger dalam bahasa jawa). Data skalar dirujuk dengan nama berawalan simbol $, data larik dirujuk dengan nama berawalan , dan data asosiasi dirujuk dengan nama berawalan %. Untuk menempelkan data dan namanya, gunakan perintah dengan simbol =. Contoh:
$name = "Bambang Prastowo"; $alamat = "Kingston, Canada"; @warna = ("Hijau", "Kuning", "Biru", "merah"); %menu = ("Senin" => "Soto Ayam", "Selasa" => "Sayur Lodeh", "Rabu" => "Rendang", "Kamis" => "Sambal Balado");
Karena dipakai dalam contoh berikutnya, sebaiknya contoh-contoh ini dieditkan dalam satu berkas, mislnya contoh.pl. Untuk bisa dijalankan dengan command
perl contoh.pl
Dalam contoh-contoh berikut, akan banyak dilakukan perintah print. Untuk memudahkan melihat hasil yang dimaui, perintah print (dan lain-lain) yang tidak diperlukan bisa dilewati saja kalau depannya diberi tanda pagar #. Jadi
# print "bla bla bla";
tidak akan dianggap sebagai bagian dari program.
Anggota larik bisa dirujuk dengan indeks posisinya dalam larik. Anggota pertama dirujuk dengan index posisi 0, yang kedua berindex 1, yang ketiga berindex 2, dan seterusnya. Jadi, kalau kita ketikkan perintah
print $warna[2];
Akan menampilkan skalar "Biru". Perhatikan, peindeksan itu memakai awalan $, bukan . Ini menunjukkan bahwa dia merujuk ke skalar anggota @warna, bukan larik @warna itu sendiri.
Untuk merujuk ke anggota asosiasi, kita perlakukan bagian pertama dari tiap anggota asosiasi itu sebagai index. Contohnya
print $menu{"Selasa"}
menampilkan skalar "Sayur Lodeh".
Di bagian ini kita keluar sebentar dari urusan perl. Pemrosesan data dengan program macam grep, sed, awk, perl itu mengikuti filosofi saluran dan saringan data. Data disalurkan melalu beberapa saringan yang disambung-sambung dengan pipa. Contoh, kita menuliskan program:
join lokasi.dat telpon.dat > sementara.dat awk '{print "Nama: " $1; print "Lokasi: " $2; print "Telpon: " $3; print ""}' sementara.dat > daftar.dat
Join membaca data dari lokasi.dat dan telpon.dat untuk dijoin dan menuliskan hasilnya ke berkas sementara.dat. Awk membaca sementara.dat mengolahnya dan menuliskan hasilnya ke daftar.dat.
Dua perintah ini bisa disambung langsung dengan pipa tanpa perlu menuliskan berkas sementara. Di unix dan dos, pipa ditulis dengan tanda garis tegak |. Contoh, join dan awk di atas bisa digabung menjadi
join lokasi.dat telpon.dat | awk '{print "Nama: " $1; print "Lokasi: " $2; print "Telpon: " $3; print ""}' sementara.dat > daftar.dat
Didalam program perl, data bisa dianggap mengalir dari dan ke berkas. Untuk bisa membuka aliran data, kita gunakan perintah open. Contoh, dalam perl kita bisa buka saluran data dari berkas lokasi.dat dengan
open(LOK, "lokasi.dat");
Setelah open itu, baris baris di berkas lokasi.dat bisa dibaca baris per baris dengan perintah penempelan data ke nama dari saluran <LOK>, misalnya
$lok = <LOK>; print $lok;
akan menampilkan baris pertama dari berkas "lokasi.dat". Kalau kita ulang perintah
$lok = <LOK>; print $lok;
maka $lok akan merujuk ke baris berikutnya dari berkas "lokasi.dat" dan seterusnya.
Jika yang disebelah kiri tanda sama dengan itu nama data larik (pakai awalan @, bukan $), maka semua data akan tesedot habis ke situ (berkasnya sendiri sih masih utuh, tidak terganggu gugat). Contohnya:
open(LOK, "lokasi.dat"); @lokasi = <LOK>; print @lokasi;
menampilkan semua isi berkas lokasi.dat.
Perl menyediakan banyak sekali fungsi ``built-in''. Kita mulai dengan yang akan banyak dipakai dalam contoh berikut yaitu split. Split memotong-motong data skalar pada posisi-posisi tertentu yang bisa ditentukan sendiri dengan ekspresi regular diantara dua garis miring. Sementara, kita pakai ekspresi paling mudah yaitu spasi, / /. Contoh berikut memotong skalar "Pon Wage Kliwon Legi Pahing" pada tiap spasi menjadi larik ("Pon", "Wage", "Kliwon", "Legi", "Pahing").
@pasaran = split(/ /, "Pon Wage Kliwon Legi Pahing"); print $pasaran[3];
menampilkan skalar "Legi". Ingat bahwa, indeks larik perl mulai dari 0. Jadi print $pasaran[0] menampilkan "Pon".
Bagian dari program perl bisa diulang-ulang dengan berbagai kontrol pengulangan.
Yang sering dilakukan adalah mengulang pekerjaan untuk tiap anggota lrik. Untuk itu kita bisa gunakan foreach dengan sintaks
foreach $perujuk_data (@larik) {perintah-perintah}
Contoh, kita punya berkas lokasi.dat yang berisi:
Bambang Canada Sumedi Amerika Juwono Indonesia Dwi Jepang
Kita bisa buat program
open(LOK, "lokasi.dat"); @lokasi = <LOK>; foreach $lok (@lokasi){ @nama_lokasi = split(/ /, $lok); print $nama_lokasi[0]; }
Yang akan menampilkan "BambangSumediJuwonoDwi". Perlu diingat,
kalau tidak menjadi bagian dari skalarnya, perl tidak akan memberikan
baris baru pada tiap perintah print. Di perl, baris baru diberi kode
"
n". Untuk memisahkan nama-nama itu, bisa dicoba
print "$nama_lokasi[0]\n"; atau print "$nama_lokasi[0] ";
Pengulangan bisa dilakukan didalam badan pengulangan yang lain. Contohnya pernah kita lihat pada proses join. Menggabung data nama-lokasi dan nama-telpon, menjadi data nama-lokasi-telpon. Kita punya berkas "telpon.dat" yang berisi
Bambang 123-456-7890 Sumedi 111-222-3333 Juwono 222-333-4444 Dwi 999-888-7777
Bisa dibuat program berikut, misalnya diberi nama namaloka.pl
open(LOK, "lokasi.dat"); # buka saluran LOK dari berkas lokasi.dat @lokasi = <LOK>; # baca semua data, masukkan ke larik @lokasi open(TEL, "telpon.dat"); # @telpon = <TEL>; # foreach $lok (@lokasi){ # ulang untuk tiap anggota larik @lokasi # dirujuk dengan nama $lok chop $lok; # buang tanda baris baru di ujung akhir $lok # bandingkan hasilnya tanpa chop ini @nama_lokasi = split(/ /, $lok); # pisahkan nama dan lokasi foreach $tel (@telpon){ #pengulangan di dalam pengulangan @nama_telpon = split(/ /, $tel); if($nama_lokasi[0] eq $nama_telpon[0]){ print "$nama_telpon[0] $nama_lokasi[1] $nama_telpon[1]"; } } }
Kalau dijalankan dengan perintah
perl namaloka.pl
Akan dihasilkan
Bambang Canada 123-456-7890 Sumedi Amerika 111-222-3333 Juwono Indonesia 222-333-4444 Dwi Jepang 999-888-7777
Bisa dirapikan (seperti contoh awk terdahulu) dengan mengganti perintah print itu dengan
print "Nama:$nama_telpon[0]\n", "Lokasi:$nama_lokasi[1]\n", "Telpon:$nama_telpon[1]";
Ingat, "\n"
itu adalah kode untuk baris baru.
Contoh namaloka.pl di atas memakai perintah bersyarat if. Perintah bersyarat adalah perintah yang dijalan kalau syarat tertentu dipenuhi. Perintah bersyarat diawali dengan kata if, diikuti syarat dalam tanda kurung dan perintah-perintah dalam kurung kurawal. Perintah-perintah itu dijalankan kalau syarat dalam tanda kurung itu terpenuhi. Dalam contoh namaloka.pl di atas, print dijalankan kalau bagian nama dari nama_lokasi sama (eq, equal) dengan bagian nama dari nama_telpon.
Dalam contoh di atas, nama, lokasi, dan kota terdiri dari satu kata saja yang dipisahkan dengan satu spasi. Dalam kenyataan, nama lengkap kebanyakan terdiri dari dua kata atau lebih. Demikian pula lokasi bisa diisi dengan alamat lengkap.
Buat contoh data nama alamat dengan nama-nama lengkap dan lokasi
berupa alamat jalan, nomor, kota dsb. Ubah program namaloka.pl
sehingga bisa menangani data itu. Petunjuk: gunakan simbol pemisah
titik dua dan split dengan pemisah /:/
.
Dalam contoh namaloka.pl di atas, nama berkas yang diolah (lokasi.dat dan telpon.dat) dituliskan sebagai bagian dari program itu sendiri. Demikian pula dengan simbol pembatas spasi. Sering kita ingin membuat program fleksibel bisa diterapkan ke nama berkas yang lain. Untuk menangkap informasi dari luar program, kita gunakan larik @ARGV. Larik ini akan terisi kata-kata yang diketikkan pada saat menjalankan program. Misalnya, kalau kita ketikkan
perl namaloka.pl lokasi.dat telpon.dat
maka kata-kata setelah nama program manaloka.pl bisa ditangkap dari
dalam program dengan membaca larik @ARGV
. Dari contoh itu,
$ARGV[0]
berisi skalar "lokasi.dat" dan $ARGV[1]
berisi skalar "telpon.dat". Dengan cara itu, pembukaan saluran
data bisa merujuk ke isi larik @ARGV. Misalnya dengan
open(LOK, $ARGV[0]);
dan open(TEL, $ARGV[1])
;
Untuk membuat program fleksibel, kita bisa juga member spesifikasi simbol pemisah dari luar program. Misalnya dengan mengetikkan
perl namaloka.pl lokasi.dat telpon.dat : | | | $ARGV[0] $ARGV[1] $ARGV[2]
Dan pemisahan data nama lokasi dilakukan dengan
split(/$ARGV[2]/, $lok);
Kalau baris-baris datanya menggunakan simbol pemisah :.
Informasi yang dimasukkan dari luar program semacam ini disebut parameter (kadang disebut juga dengan argumen). Pada dasarnya, makin banyak parameter, makin fleksibel kegunaan program itu. Akan tetapi, biasanya program yang terlalu banyak parameternya akan membingungkan pemakaiannya.
Ekspresi regular atau sering disebut regex adalah skalar yang mewakili sekelompok skalar-skalar yang lain dengan cara menggunakan kode-kode tertentu. Biasanya, regex ditulis diantara dua garis miring. Berikut ini adalah contoh beberapa regex versi perl yang sering ter(saya)pakai:
/./ mewakili skalar satu simbol apa saja /../ mewakili skalar dua simbol apa saja
huruf-huruf dan angka-angka mewakili dirinya sendiri, jadi
/Bambang/ mewakili skalar "Bambang".
Simbol yang sama
berjajar bisa dinyatakan dengan tambahan kode * atau +. *
berarti nol atau lebih, + berarti satu atau lebih.
/Bambang*/
mewakili "Bamban", "Bambang", "Bambangg", "Bambanggg", dst.
/Bambang+/ mewakili "Bambang", "Bambangg", "Bambanggg",
dst.
/ +/
mewakili satu spasi atau lebih (sering dipakai sebagai pemisah dalam
perintah split.
Untuk merujuk ke simbol yang dipakai sebagai kode regex, gunakan garis miring
terbalik Jadi
/\./
mewakili skalar "."
/\*\*\+\./
mewakili skalar "**+.".
Tab, yang sering tertampilkan sebagai beberapa spasi yang memenuhi
sampai kolom tertentu, ditulis dengan . Angka diwakili dengan
\d
(singkatan digit). Jadi skalar angka bilangan bulat bisa
diwakili dengan /\d+/
yang bararti satu digit atau lebih "0", "1", "2", ..., "10", ..., "100" dan seterusnya. Angka desimal
pecahan bisa diwakili dengan /\d+\.\d*/
yang berarti satu atau
lebih digit, diikuti dengan titik, diikuti dengan nol atau lebih
digit.
Tanda kurung bisa dipakai untuk mengelompokkan bagian dari regex yang terpengaruh kode. Misalnya /(dor)+/ mewakili "dor", "dordor", "dordordor", dst. /cas(cis)*cus/ mewakili "cascus", "casciscus", "cascisciscus", dst.
Oprator pembanding =~
punya dua fungsi:
Untuk contoh berikut, gunakan berkas dir.dat yang isinya:
Volume in drive D is /hda6/dos Directory of D:\PERL\CONTOH . <DIR> 07-24-95 11:53a .. <DIR> 07-12-95 10:02a DIR DAT 37 07-24-95 11:53a LOKASI DAT 58 07-23-95 8:01p TELPON DAT 78 07-23-95 8:02p DAFTAR DAT 202 06-21-95 12:45a JOIN PL 266 07-12-95 10:30a SEMENTAR DAT 108 07-12-95 10:21a OPENFILE PL 62 07-21-95 10:57a FORMAT AWK 145 07-14-95 3:48a ASO PL 83 07-21-95 10:24a ULANG PL 98 07-21-95 11:20a SPLIT DAT 77 07-21-95 11:51a NAMA PL 142 07-21-95 11:57a SYSTEM PL 15 07-24-95 11:51a NAMALOKA PL 743 07-23-95 8:04p 16 file(s) 2114 bytes 76365824 bytes free
Data semacam ini bisa diperoleh dengan mengetikkan dir > dir.dat Di DOS. Bagi yang menggunakan unix, gunakan saja data di atas.
Misalnya kita hendak memilih baris-baris dari dir.dat dari nama program perl. Dalam contoh, nama program perl berakhiran PL. Maka kita print baris itu kalau mengandung "PL".
open(DIR, "dir.dat"); @dir = <DIR>; foreach $baris (@dir){ if($baris =~ /PL/){ print $baris; } }
Program di atas kurang sempurna karena baris
"SPLIT DAT 77 07-21-95 11:51a"
ikut tersaring. Disini kita dituntut untuk berkreasi. Misalnya, syarat
print diatas bisa kita ubah menjadi ($baris =~ / PL /
) mengharuskan PL
yang dicari diapit spasi.
Perl mengistimewakan nama data yang terdiri dari satu simbol garis
bawah $_
.
Beberapa fungsi bisa dijalankan tanpa menyebut nama
data inputnya. Jika tidak disebut nama, maka yang dimaksud adalah data yang
bernama $_
.
Secara umum, nama $_
bisa dipakai untuk merujuk skalar sebagaimana
nama-nama yang lain. Misalnya
open(DIR, "dir.dat"); @dir = <DIR>; foreach $_ (@dir){ $_ =~ s/95/1995/; print $_; }
Secara khusus, kontrol foreach itu bisa diganti for, tanpa menyebutkan
nama rujukan $_
(sudah dianggap ada dari sononya).
for (@dir){ $_ =~ s/95/1995/; print $_; }
Jika dikenakan pada $_
, operator =~
tidak perlu
menyebutkan $_
.
for (@dir){ s/95/1995/; print $_; }
Perintah print $_
; juga tidak perlu menyebutkan $_
.
Contoh program melengkapi angka tahun diatas bisa ditulis demikian:
open(DIR, "dir.dat"); @dir = <DIR>; for (@dir){ s/95/1995/; print; }
Dengan bawaan, contoh program namaloka.pl di 5.2 bisa disederhanakan menjadi
open(LOK, "lokasi.dat"); # buka saluran LOK dari berkas lokasi.dat @lokasi = <LOK>; # baca semua data, masukkan ke larik @lokasi open(TEL, "telpon.dat"); # @telpon = <TEL>; # for (@lokasi){ # ulang untuk tiap anggota larik @lokasi # dirujuk dengan nama $_ chop; # chop $_ bisa ditulis chop saja @nama_lokasi = split; # tanpa keterangan tambahan, split akan # berlaku seperti split(/[ \t]+/, $_) for (@telpon){ @nama_telpon = split; if($nama_lokasi[0] eq $nama_telpon[0]){ print "$nama_telpon[0] $nama_lokasi[1] $nama_telpon[1]\n"; } } }
Kontrol dalam pengulangan dan perintah bersyarat punya bentuk yang sama. Keduanya berbeda fungsi saja. Dalam pengulangan, kontrol dipakai untuk menentukan perlu tidaknya kelompok perintah diulang lagi. Dalam perintah bersyarat, kontrol dipakai untuk menentuka dikerjakan atau tidaknya sekelompok perintah. Ada tiga macam kontrol: bentuk perbandingan, nilai dan kesuksesan. Sebagai kontrol, semuanya akan diinterpretasikan sebagai "ya" atau "tidak" terhadap dijalankannya perintah-perintah yang dikontrol.
Ini yang paling mudah difahami. Kita membandingakan dua skalar. Jika yang kita bandingkan adalah urutan abjadnya, perbandingan menggunakan operator lt, gt, le, ge, eq, dan ne sebagai perbandingan lebih kecil, lebih besar, lebih kecil atau sama, lebih besar atau sama, sama, dan tidak sama. Jika kita membandingkan skalar sebagai angka, maka operator pembandingnya memakai simbol <, >, <=, >=, ==, dan !=. Nilai "ya" atau "tidak" nya kontrol perbandingan saya kita sudah jelas.
Kontrol nilai punya interpretasi sebagai berikut:
""
, bernilai ``tidak''
"0"
, bernilai ``tidak''
Silakan bereksperimen dengan baris baris berikut, pelajari baik-baik hasilnya:
if(0) {print "testing kontrol (0) \n";} if(1) {print "testing kontrol (1) \n";} if("") {print "testing kontrol (\"\") \n";} if("0") {print "testing kontrol (\"0\") \n";} if("00") {print "testing kontrol (\"00\") \n";} if("2-2") {print "testing kontrol (\"2-2\") \n";} if("2" - "2"){print "testing kontrol (\"2\" - \"2\") \n";}
Beberapa perintah yang berhubungan dengan hal-hal diluar program misalnya membuka saluran data dari dan ke berkas, dalam kontrol bisa dinterpertasikan sebagai sebagai ``ya'' atau ``tidak'' tergantung kesuksesan perintah itu. Misalnya:
if (open(DATA, "lokasi.dat")) { print <DATA>;} else {print "lokasi.dat tidak bisa dibuka\n";}
else {...}
adalah perintah yang bisa dituliskan setelah perintah
bersyarat. Ini bisa dipakai untuk menjalankan perintah-perintah dalam
tanda kurung kurawal itu sebagai alternatif, sekiranya kontrol dalam
perintah bersyarat sebelumnya itu berniai ``tidak''.
Dalam contoh sebelum ini, untuk diolah, data dari berkas dimasukkan semua sekaligus ke dalam larik seperti
open(DIR, "dir.dat"); @dir = <DIR>;
yang menyalin isi dir.dat
ke larik @dir
semuanya
sekaligus. Jika dir.dat
berukuran raksasa, @dir = <DIR>
bisa mengakibatkan sistem kehabisan memori (out of memory
).
Untuk mengatasi masalah memori ini, data bisa diambil dan diolah
satu per satu. Misalnya:
open(DIR, "dir.dat"); while ( $baris = <DIR>) { $baris =~ s/95/1995/; print $baris; }atau
open(DIR, "dir.dat"); while(<DIR>){ s/95/1995/; print; }
Perintah while
adalah cara lain membuat pengulangan. Bentuknya
while(kontrol){...}Perintah-perintah dalam kurung kurawal dijalan kalau kontrolnya bernilai ``ya''. Setelah selesai, kontrol kembali diinterpretasikan, kalau nilainya masih ``ya'', perintah-perintah dalam kurung kurawal di jalankan lagi.
Ingat bahwa $baris = <DIR>
mengambil data dari saluran DIR
baris-perbaris. Setelah data habis, maka perintah itu akan gagal
sehingga sebagai kontrol, interpretasinya dalah ``tidak''.
Contoh while
kedua itu menggunakan bawaan, baris dioleh dengan
nama $_
yang menurut perjanjian tidak perlu dituliskan.