Metakarakter

Metakarakter ., *, +, dan ?, anchor ^ dan $, serta alternasi | untuk menggambarkan pola yang bervariasi.

Daftar isi

Pola literal hanya mampu mencocokkan teks yang persis sama, sedangkan teks nyata jarang seragam seperti itu. Metakarakter (metacharacter) adalah karakter khusus di dalam pola yang menggambarkan variasi, mulai dari ., *, +, dan ?, hingga anchor ^ dan $ serta alternasi |. Topik ini membahas kegunaan masing-masing metakarakter tersebut beserta contoh eksekusinya, termasuk perilaku greedy yang menjadi sumber kesalahan paling umum. Setiap metakarakter diperagakan dengan skrip nyata, sehingga perilakunya dapat diverifikasi ulang tanpa menebak.

Titik sebagai pencocok satu karakter#

Metakarakter . mencocokkan tepat satu karakter apa pun, termasuk spasi dan tanda baca, tetapi tidak termasuk baris baru pada pencocokan biasa. Pola piket.Citra dengan demikian mencocokkan piket diikuti satu karakter apa pun lalu Citra. Skrip berikut menguji pola itu terhadap beberapa kemungkinan tulisan jadwal piket:

perl titik.pl
#!/usr/bin/env perl
use strict;
use warnings;

my @jadwal = ("piket Citra", "piket  Citra", "piket-Citra", "piket Citras");

foreach my $baris (@jadwal) {
    # . mencocokkan tepat satu karakter apa pun
    if ($baris =~ m/piket.Citra/) {
        print "Cocok : $baris\n";
    } else {
        print "Gagal : $baris\n";
    }
}

# titik literal ditulis \.
print "jadwal.txt dikenali\n" if "jadwal.txt" =~ m/jadwal\.txt/;
print "jadwalXtxt ikut cocok tanpa \\.\n" if "jadwalXtxt" =~ m/jadwal.txt/;
text Keluaran
Cocok : piket Citra
Gagal : piket  Citra
Cocok : piket-Citra
Cocok : piket Citras
jadwal.txt dikenali
jadwalXtxt ikut cocok tanpa \.

Pemisah satu karakter apa pun lolos, sedangkan dua spasi beruntun gagal karena . hanya menanggung satu karakter. Baris keempat tetap cocok meskipun ada tambahan huruf s di ujungnya, karena pencocokan tidak diikat pada awal dan akhir string. Di baris terakhir, pola jadwal.txt tanpa escape ikut mencocokkan jadwalXtxt, sehingga titik literal selalu ditulis \. ketika nama berkas atau alamat yang diperiksa memuat titik sungguhan.

Titik menjadi metakarakter yang paling sering disalahpahami karena penampilannya sama dengan titik biasa. Aturan praktisnya sederhana, yaitu setiap titik dalam pola yang dimaksudkan sebagai titik literal harus ditulis \.. Sebaliknya, . juga berguna sebagai pengisi satu posisi yang isinya tidak penting, misalnya pola a.c yang cocok dengan abc, a c, maupun a-c. Satu-satunya karakter yang tidak dicocokkan . adalah baris baru, sehingga titik tidak melompati batas baris pada pencocokan biasa.

Quantifier * + dan ?#

Quantifier menyatakan berapa kali karakter atau kelompok sebelumnya boleh muncul. Tanda * berarti nol kali atau lebih, tanda + berarti satu kali atau lebih, sedangkan tanda ? berarti nol kali atau satu kali, yaitu bagian opsional. Skrip berikut menguji ketiganya terhadap tiga nama berkas yang jumlah tanda hubungnya berbeda:

perl quantifier.pl
#!/usr/bin/env perl
use strict;
use warnings;

my @berkas = ("jadwal20.txt", "jadwal-20.txt", "jadwal--20.txt");

foreach my $nama (@berkas) {
    my $hasil = "";
    $hasil .= "*" if $nama =~ m/jadwal-*20/;
    $hasil .= "+" if $nama =~ m/jadwal-+20/;
    $hasil .= "?" if $nama =~ m/jadwal-?20/;
    print "$nama : $hasil\n";
}
text Keluaran
jadwal20.txt : *?
jadwal-20.txt : *+?
jadwal--20.txt : *+

Matriks pada keluaran memperlihatkan perbedaan ketiganya secara langsung. Quantifier * cocok pada ketiga nama karena nol tanda hubung sudah cukup, + menuntut minimal satu tanda hubung, dan ? hanya menerima nol atau satu tanda hubung. Perlu diketahui bahwa quantifier secara default berperilaku greedy, yaitu menelan sebanyak mungkin karakter. Pada teks piket <Ali> lalu <Budi>, pola <.*> mencakup <Ali> lalu <Budi> seluruhnya dan tidak berhenti pada tanda > pertama. Menambahkan ? setelah quantifier membalik perilakunya:

bash
# * bersifat greedy, sedangkan *? berhenti pada kecocokan pertama
perl -e 'use strict; use warnings; my $teks = "piket <Ali> lalu <Budi>"; print "Greedy: $&\n" if $teks =~ m/<.*>/; print "Ringkas: $&\n" if $teks =~ m/<.*?>/' 2>&1
text Keluaran
Greedy: <Ali> lalu <Budi>
Ringkas: <Ali>

Ketiga quantifier selalu menempel pada satu unsur di sebelah kirinya, dan unsur itu dapat berupa satu karakter, kelas karakter, atau grup. Salah membaca jangkauan quantifier adalah kesalahan yang lazim, misalnya menganggap abc* berarti abc yang berulang, padahal yang berulang hanyalah huruf c. Perl juga menyediakan quantifier rentang seperti {2,4} untuk jumlah pengulangan yang perlu dikunci, sehingga tanda * dan + cukup digunakan ketika jumlahnya memang bebas.

Anchor ^ dan $#

Anchor tidak mencocokkan karakter, melainkan posisi. Anchor ^ menandai awal string, sedangkan $ menandai akhir string. Tanpa anchor, pola ERROR cocok pada baris catatan log mana pun yang memuat kata itu, termasuk baris yang ERROR-nya hanya berada di tengah kalimat. Skrip berikut membandingkan pencocokan dengan dan tanpa anchor ^, lalu menutup dengan anchor $. Dua anchor itu sering digunakan berpasangan untuk memvalidasi bentuk utuh sebuah teks, karena pola yang tidak dianchor tetap dapat lolos meskipun hanya cocok pada sebagian barisnya:

perl anchor.pl
#!/usr/bin/env perl
use strict;
use warnings;

my @log = (
    "ERROR: koneksi terputus",
    "INFO: sinkronisasi selesai",
    "WARNING: entri ERROR lama diarsip",
);

foreach my $baris (@log) {
    print "Tanpa ^ : $baris\n" if $baris =~ m/ERROR/;
    print "Dengan ^: $baris\n" if $baris =~ m/^ERROR/;
    print "---\n";
}

my @berkas = ("catatan.txt", "catatan.txt.bak");

foreach my $nama (@berkas) {
    print "Berujung .txt : $nama\n" if $nama =~ m/\.txt$/;
    print "Berujung .bak : $nama\n" if $nama =~ m/\.bak$/;
}
text Keluaran
Tanpa ^ : ERROR: koneksi terputus
Dengan ^: ERROR: koneksi terputus
---
---
Tanpa ^ : WARNING: entri ERROR lama diarsip
---
Berujung .txt : catatan.txt
Berujung .bak : catatan.txt.bak

Baris WARNING hanya lolos pola tanpa ^, karena kata ERROR di dalamnya berada di tengah. Pada pengujian kedua, \.txt$ menolak catatan.txt.bak karena akhirnya bukan .txt. Menggabungkan keduanya seperti pada m/^ERROR:/ membuat pola terikat pada posisi tertentu, dan kombinasi ^ serta $ dalam satu pola mengunci kecocokan pada string yang utuh.

Sebagai contoh, pola m/^catatan$/ hanya cocok dengan string yang isinya persis catatan. Anchor $ juga menoleransi satu baris baru di ujung string, sehingga string yang diakhiri \n tetap cocok dengan pola yang berujung $. Anchor juga umumnya membuat pencocokan lebih cepat, karena kegagalan dapat ditolak sejak posisi pertama tanpa memindai seluruh string.

Alternasi |#

Alternasi | berarti “atau”, sehingga pola Senin|Kamis mencocokkan string yang memuat Senin atau Kamis. Alternasi adalah cara paling langsung untuk menggambarkan beberapa kemungkinan tulisan dalam satu pola. Skrip berikut memilih hari piket dari sebuah daftar:

perl alternasi.pl
#!/usr/bin/env perl
use strict;
use warnings;

my @hari = ("Senin", "Selasa", "Rabu", "Kamis");

foreach my $hari (@hari) {
    print "Piket: $hari\n" if $hari =~ m/Senin|Kamis/;
}

# alternasi berlaku sampai ujung pola, bukan hanya kata di sekitarnya
print "Cocok pada 'kucing hitam'\n" if "kucing hitam" =~ m/kucing hitam|putih/;
print "Cocok juga pada 'anjing putih'\n" if "anjing putih" =~ m/kucing hitam|putih/;
text Keluaran
Piket: Senin
Piket: Kamis
Cocok pada 'kucing hitam'
Cocok juga pada 'anjing putih'

Dua baris terakhir memperlihatkan jebakan jangkauan alternasi. Pola kucing hitam|putih berarti kucing hitam atau putih, bukan kucing hitam atau kucing putih, karena | memisahkan seluruh bagian di kiri dan kanannya. Akibatnya string anjing putih ikut cocok karena memuat putih. Jangkauan alternasi dibatasi dengan tanda kurung, dan tanda kurung itu sendiri dibahas pada bagian grup dan capture.

Alternasi dicocokkan dari kiri ke kanan, sehingga urutan pilihan menentukan bagian mana yang dicocokkan lebih dahulu. Untuk pengujian boolean, urutan tersebut tidak mengubah hasil akhir, tetapi pilihan yang paling sering muncul sebaiknya diletakkan di kiri. Ketika jumlah pilihan bertambah dan beberapa pilihan berbagi awalan yang sama, pola dapat dirapikan dengan mengelompokkan awalan itu bersama tanda kurung.

Perlu diperhatikan bahwa alternasi mencocokkan potongan teks, bukan kata utuh, sehingga pola Senin|Kamis juga menemukan Senin pada string Senin pagi maupun Kamis pada Rabu-Kamis. Apabila kecocokan harus terbatas pada kata yang lengkap, spasi atau batas lain perlu dinyatakan secara eksplisit di sekitar alternasi tersebut. Tanpa pengelompokan, elemen tambahan itu hanya melekat pada pilihan terakhir, sehingga pilihan lain tetap bebas dicocokkan di posisi mana pun.

Ringkasan#

  • . mencocokkan tepat satu karakter apa pun, dan titik literal ditulis \. agar tidak salah makna.
  • * berarti nol kali atau lebih, + berarti satu kali atau lebih, dan ? berarti opsional, dengan perilaku greedy sebagai default dan akhiran ? untuk membaliknya.
  • ^ dan $ menandai posisi awal dan akhir string, sehingga mengikat kecocokan pada tempat yang tepat.
  • | menyatakan “atau” dengan jangkauan sampai ujung pola, sehingga pengelompokan dengan tanda kurung diperlukan bila alternasi harus terbatas.

Referensi#