Wednesday, October 31, 2012

Masalah menggunakan Perl sebaris dlm Windows

Penggunaan Perl sebaris (one-liner) dalam Windows amnya tidaklah rumit atau bermasalah. Tetapi ada masanya masalah tertentu akan timbul disebabkan peraturan-peraturan tertentu dalam prom arahan (command-prompt) Windows.

Contohnya, baru-baru ini saya terjumpa satu kaedah yang mencadangkan penggunaan pemboleh ubah persekitaran (environment variable) dalam Perl sebaris. Bagusnya kaedah ini ialah jika Perl sebaris kita terlalu panjang (untuk kod satu baris) tetapi kerap digunakan, kita boleh mengurangkan kerja menaip (andaikan kita tidak mahu guna fail batch). Contohnya bagi Perl sebaris berikut,
perl -ne  "print if /^[+-]?([0-9]+[.]?[0-9]*|[.][0-9]+)([eE][+-]?[0-9]+)?$/" file.txt
bukan saja hendak menulis, bahkan hendak menghafalnya pun sudah rumit. Maka kita boleh gunakan pemboleh ubah persekitaran. Arahan berikut membentuk satu pemboleh ubah baru bernama format_nombor :
set format_nombor="^[+-]?([0-9]+[.]?[0-9]*|[.][0-9]+)([eE][+-]?[0-9]+)?$"
(dwi-quot diperlukan kerana jika tidak ada, arahan SET tidak berjaya. Tapi masalah lain pula timbul, dan dibincangkan di bawah) Jadi sepatutnya saya boleh gunakan interpolasi nilai pemboleh ubah ke dalam arahan Perl sebaris seperti berikut, sekaligus memudahkan penulisan arahan Perl sebaris,
perl -ne  "print if /%format_nombor%/" file.txt
Malangnya ini tidak berjaya kerana Windows merungut dengan mesej berikut,
'[.][0-9]+)' is not recognized as an internal or external command, operable program or batch file.
Apa masalahnya? Masalahnya ialah hasil interpolasi tidak seperti yang dijangka! Lihat hasil di bawah ini:
perl -ne  "print if /"^[+-]?([0-9]+[.]?[0-9]*|[.][0-9]+)([eE][+-]?[0-9]+)?$"/" file.txt
Perhatikan sepasang dwi-quot yang terhasil dalam dwi-quot. Jadi Perl sebaris yang terhasil tidak sah! 

Masalah ini sebenarnya berpunca daripada nilai dalam %format_nombor% yang sudahpun mempunyai dwi-quot (boleh dilihat dengan arahan SET %format_nombor%). Maka bila diinterpolasi, dwi-quot itu akan turut serta sebagai sebahagian nilai pemboleh ubah. 

Untuk menyelesaikan masalah ini, dwi-quot itu perlu dibuang daripada nilai %format_nombor%. Hal ini mulanya memeningkan kerana dalam arahan SET dwi-quot itu diperlukan. Setelah puas mencari, rupa-rupanya arahan SET dengan dwi-quot itu boleh ditulis dengan cara lain. Caranya ialah seperti di bawah ini (kedudukan dwi-quot bermula sebelum nama pemboleh ubah, dan bukan setakat merangkumi nilai),
set "format_nombor=^[+-]?([0-9]+[.]?[0-9]*|[.][0-9]+)([eE][+-]?[0-9]+)?$"
Selepas menggunakan cara ini, dwi-quot sudah tidak ada dalam nilai %format_nombor% (boleh dipaparkan menggunakan arahan SET %format_nombor%). Maka apabila diinterpolasi sudah tidak ada masalah.
perl -ne  "print if /%format_nombor%/" file.txt
Maka setelah berjaya menemui kaedah ini, penggunaan Perl sebaris yang agak panjang dapat dipermudahkan.

Habis cerita.


Notakaki
  1. Kod Perl sebaris itu sebenarnya berfungsi mencari nombor-nombor yang sah (mengikut standard IEEE) dalam setiap baris fail input (fail.txt). Setiap nombor yang sah akan dipaparkan. Nombor hanya dikesan jika terdapat satu nombor dalam setiap baris.
  2. Untuk membuang pemboleh ubah yang kita isytiharkan, gunakan arahan SET tanpa nilai, seperti berikut,
  3. set format_nombor=
  4. Selain kaedah di atas, pemboleh ubah persekitaran bagi Windows sebenarnya boleh dibentuk/disunting melalui antaramuka GUI (klik kanan pada ikon My Computer->Properties. Cari tab Environment variables dan tambah pemboleh ubah dengan nilai yang diperlukan)

Menggunakan ekspresi regular dengan Perl

Kali ini saya ingin memperkatakan tentang satu lagi kelebihan bahasa pengaturcaraan Perl iaitu penggunaan ekspresi regularnya.

Ekspresi regular (regular expression) ialah notasi yang digunakan bagi menyatakan suatu corak atau susunan am aksara atau simbol. Misalnya 'yunus' untuk perkataan 'yunus', '\d+' menyatakan corak am suatu nombor ('\d' mewakili 1 digit, '\d+' mewakili 1 atau lebih digit). Asasnya ekspresi regular sangat berguna untuk proses mencari segolongan teks tertentu dalam suatu teks spt. mengesan kehadiran perkataan 'perl' dalam teks 'bahasa pengaturcaraan perl' (secara teknikalnya disebut mencari sub-rentetan dalam suatu rentetan), atau menentusahkan format tertentu bagi suatu teks (seperti format matawang, tarikh dll).

Perl menggunakan notasi yang dikenali sebagai PCRE (Perl-compatible regular expression), iaitu notasi ekspresi regular dengan simbol-simbol khas yang diperkenalkan dalam bahasa Perl. Sesetengahnya diterapkan oleh bahasa-bahasa pengaturcaraan lain. Amnya notasi ini memadankan aksara dengan aksara. Maknanya notasi 'Yunus' akan sepadan dengan teks 'Yunus'. Selain itu terdapat juga meta-aksara seperti '.', '*', '+', '[...]' dsb. Misalnya jika kita ingin mencari suatu teks yang hanya mengandungi digit-digit, kita boleh menggunakan ekspresi regular '\d+'; atau memadankan teks berformat tarikh dengan corak am '\d\d\/\d\d\/\d{4}'.

Berikut adalah sebahagian notasi PCRE dan maksudnya (untuk maklumat lanjut boleh rujuk tutorial PerlRE),
  • a-z = mewakili set huruf/simbol 'a' hingga 'z'
  • \d =  mewakili digit antara 0 hingga 9
  • \d+ = mewakili 1 atau lebih digit
  • . = 'dot', mewakili semua aksara
  • .+ = mewakili 1 atau lebih jujukan aksara selain daripada aksara penamat baris (newline)
dll.

Perl menyediakan kemudahan (dalam bentuk operator) yang membolehkan pengatur cara menggunakan ekspresi regular dalam atur cara. Operator-operator yang boleh digunakan ialah seperti berikut:
  • m/corak/ - m(atch) ialah operator yang digunakan bagi memadankan (mencari) corak dalam suatu rentetan. Misalnya,
if ($teks =~ m/foo/) {
    # buat sesuatu jika corak 'foo' dijumpai dalam $teks
}
  • s/corak/ganti/ - s(ubstitute) ialah operator yang digunakan bagi mencari padanan corak dan menggantikannya dengan teks gantian. Misalnya aturcara berikut akan mengubah $teks yang mengandungi rentetan 'fooyo' kepada 'ayoyo':
$teks = 'fooyo';
$teks =~ s/foo/ayo/;  # 'ayoyo'
  • tr/setA/setB/ - tr(ansliterate) ialah operator yang digunakan bagi memadankan susunan 'setA' dan menggantikannya dengan 'setB'. SetA dan setB mestilah jujukan huruf atau simbol. Misalnya aturcara berikut akan mengubah $teks yang mengandungi rentetan 'contoh' kepada 'CONTOH':
$teks =~ tr/a-z/A-Z/;

Aturcara berikut akan mengubah $teks yang mengubah rentetan 'contoh' kepada suatu 'teks sulit' (encrypted text) dan 'menyahkod'nya semula kepada bentuk asal:
$teks = 'contoh';
$teks =~ tr/a-z/zyxwvutsrqponmlkjihgfedcba/;  # 'xlmgls'
$teks =~ tr/zyxwvutsrqponmlkjihgfedcba/a-z/;  # 'contoh'
Selain operator ekspresi regular, ekspresi regular juga turut/boleh digunakan pada fungsi atau operator tertentu dalam Perl, misalnya operator grep { } dan split ().

Penggunaan dan kepentingan ekspresi regular sangat luas kerana ianya masih lagi dimaju dan dipertingkatkan. Begitu juga dengan aplikasinya dalam pengaturcaraan Perl mahupun bahasa pengaturcaraan yang lain. Sebagai pengatur cara, menguasai ekspresi regular dan keupayaan menggunakannya dalam Perl mungkin dapat memberi kita kelebihan atau sekurang-kurangnya memudahkan tugas pengaturcaraan.


Tuesday, October 30, 2012

Bahasa Pengaturcaraan Perl

Perl (Practical Extraction and Reporting Language) ialah bahasa pengaturcaraan terjemahan. Bahasa pengaturcaraan amnya ada dua jenis - yang terkompil (misalnya C, Java dll) dan yang diterjemah (Perl, Python dll). Bahasa terkompil dan bahasa terjemahan kedua-duanya melalui proses penterjemahan (bahasa pengaturcaraan kepada bahasa mesin) sebelum boleh dilaksanakan. Bezanya ialah dari segi proses pelaksanaan program.

Semua atur cara bahasa terkompil akan dikompil kepada fail berbentuk program. Maka proses mengkompil hanya perlu berlaku sekali sahaja kerana pengkompil tidak diperlukan untuk melaksanakan program. Manakala bahasa diterjemah akan sentiasa berada dalam bentuk skrip (kod sumber atau bahasa pengaturcaraan). Setiap kali hendak dilaksakanan, ia perlu diterjemah dan dilaksanakan oleh pengkompil (penterjemah). Maka atur cara bahasa terjemahan hanya boleh dilaksanakan dengan kehadiran pengkompil. (Atur cara bahasa terjemahan biasanya dipanggil skrip.)

Perl boleh digunakan bagi tujuan memformat dan memproses data berbentuk teks. Misalnya fail HTML (muka sesawang) boleh diformat semula ke dalam bentuk teks biasa dengan cara mengekstrak kandungan data teksnya dan mencetak semula data tersebut ke dalam fail teks tanpa HTML. Perl juga boleh digunakan bagi memuat turun kandungan pangkalan data dan mencetak laporan, membina laman sesawang (Common Gateway Interface atau CGI), mengurus tadbir pelayan, dan membina antaramuka grafik (GUI) sesebuah aplikasi.

Berikut adalah contoh skrip Perl yang mudah, iaitu untuk mencari dan menyenaraikan kedudukan nama 'Mohd Yunus' yang terkandung dalam sebuah fail teks 'dokumen.txt' ('Mohd' dan 'Yunus' mesti berada dalam baris yang sama):

use strict;

my $kata = 'Mohd Yunus';        # perkataan yang dicari
my $infile = "dokumen.txt";     # nama fail input.

open(INFILE, "<$infile") or
   die("Fail input '$infile' tidak dapat dibaca. $!");
while($_ = <INFILE>) {
    if(/$kata/) {
        print "'$kata' dikesan pada baris $.\n";
    }
}
close INFILE;
Contoh 1

Pengaturcaraan Perl agak sukar bagi pengatur cara yang baru mempelajarinya. Namun jika sudah biasa, Perl sebenarnya mudah digunakan dan ada masanya sangat berguna. Ia juga (i) bahasa yang sangat fleksibel, (ii) cukup mantap untuk melakukan tugas pemprosesan yang kompleks (walaupun Perl bukan pilihan untuk program masa-nyata.), (iii) menjadi pilihan kepada pentadbir sistem dan pembangun aplikasi sesawang, (iv) mendapat sokongan peminat atur cara sumber terbuka (open-source) dan (v) mempunyai sumber pustaka yang besar dan komprehensif (CPAN.org). Namun Perl lebih dikenali kerana mula-mula memperkenalkan operator ekspresi regular (regular expression) dalam bahasa atur cara, sehinggakan notasi standard Perl-compatible regular expression sering dijadikan rujukan oleh pengkompil dan enjin-enjin ekspresi regular yang terkemudian daripadanya.

Bagi yang ingin menggunakan Perl, boleh muat turun penterjemah Perl daripada Perl.org. Penterjemah diperlukan untuk melaksana skrip Perl. Pastikan penterjemah yang dimuat turun sesuai dengan sistem pengoperasian yang anda gunakan. Bagi pengguna sistem pengoperasian Linux dan Unix, tidak perlu pasang lagi kerana Perl sudah disediakan.

Ada dua kaedah melaksanakan skrip Perl (selain digunakan sebagai aplikasi CGI). Kaedah pertama ialah dengan membina skrip Perl dalam bentuk fail (yang diberi sambungan *.pl atau *.plx). Kemudian melaksanakan program penterjemah Perl dengan fail skrip sebagai parameter. Misalnya skrip berikut ditulis dalam fail skrip 'hello.pl',

print ("Hello dari Perl\n");

Skrip ini boleh dilaksanakan dengan menggunakan arahan berikut pada prom arahan (contoh berikut untuk prom sistem Windows),

c:\perl hello.pl

yang akan menghasilkan output berikut:

Hello dari Perl

Kaedah kedua ialah dengan menggunakan Perl sebaris (one-liner). Pelaksanaan Perl sebaris tidak memerlukan kita membina fail skrip kerana boleh dilaksanakan terus pada prom arahan. Skrip di atas boleh dilaksanakan terus pada prom arahan seperti berikut (dengan penanda pilihan -e),

perl -e "print (\"Hello dari Perl\n\")"

yang memberikan output yang sama. Perl sebaris hanya digunakan bagi atur cara yang ringkas. Namun ada juga atur cara Perl yang nampak seolah kompleks tetapi boleh dipadatkan menjadi Perl sebaris. Misalnya Contoh 1 di atas sebenarnya boleh dipadatkan menjadi Perl sebaris berikut:
perl -e "print grep { /Mohd Yunus/ } <>"  dokumen.txt
Atau
perl -lne "print if /Mohd Yunus/"  dokumen.txt

(Lihat contoh-contoh lain 'Perl sebaris')

Maklumat yang dipaparkan ini hanyalah pengenalan ringkas mengenai Perl. Maklumat lanjut berkenaan Perl boleh dirujuk di Perl.org.



Thursday, October 18, 2012

Perl one-liner ( untuk Perl-geek sahaja :)

Semalam ada seorang kawan sefakulti mengemukakan satu masalah -
Bagaimanakah caranya menukar data yang terdiri daripada berbilang baris, kepada satu rentetan mengandungi data-data tersebut yang hanya diselangi dengan koma (tanpa penyuntingan)?

Seperti berikut: 

aaaaa
bbbbb
ccccc

kepada 

aaaaa,bbbbb,ccccc

Satu cara yang boleh digunakan ialah dengan menggunakan fungsi dlm MS-Excell (diperoleh daripada sumber di Youtube, terima kasih Dr. Alfian FSKTM).

Tetapi yang terlintas di fikiran saya ialah dengan menggunakan Perl one-liner. Perl one-liner ialah pembentukan skrip bahasa Perl yang ringkas dan mampu dilaksanakan secara terus menerusi prom arahan atau baris arahan sahaja (berbanding menulis di dalam fail skrip Perl, *.pl)

Skrip yang boleh digunakan adalah seperti berikut: ('multilines.txt' mengandungi data input, dan output akan disimpan dalam fail 'output.txt' tanpa mengubah kandungan 'multilines.txt')

perl -e "print(join(',', map{chomp; $_;} <>))" multilines.txt > output.txt

Skrip setara (tanpa kurungan '()'):

perl -e "print join ',', map{chomp; $_;} <>" multilines.txt > output.txt

Skrip di bawah memperoleh hasil yang sama, justeru boleh digunakan sebagai skrip alternatif (sebahagiannya telah diperbaiki oleh Dr. KA, FSKTM):

perl -e "$_ = join (',', <>); s/\n\r?//g; print" multilines.txt > output.txt

Berikut adalah contoh perlaksanaannya dalam prom arahan Windows (arahan 'more' sekadar memperlihatkan kandungan fail input, dan output yang terhasil):

C:\>more multilines.txt
xxxx
yyyy
zzzz

C:\>perl -e "print(join(',', map{chomp; $_;} <>))" multilines.txt > output.txt

C:\>more output.txt
xxxx,yyyy,zzzz

P/s: Bagi yang tidak biasa atau baru menggunakan Perl, pengguna Windows OS kena install penterjemah Perl dahulu (Unix dan Linux sudah ada versi Perl yang dipasang).


[ Kemaskini: 19 Okt 2012 ]

Semua perkataan 'Perl-liner' diubah. Istilah yang sebenar ialah 'Perl one-liner'.