Grup dan capture

Grup () untuk mengelompokkan pola, capture bernomor pada $1 dan seterusnya, serta capture bernama (?<name>).

Daftar isi

Tanda kurung pada ekspresi reguler mengerjakan dua pekerjaan sekaligus, yaitu mengelompokkan bagian pola dan menyimpan potongan teks yang cocok. Hasil penyimpanan itu disebut capture, dan menjadi jembatan dari pertanyaan “apakah cocok” menuju “bagian mana yang cocok”. Topik ini membahas pengelompokan untuk alternasi dan quantifier, capture bernomor pada $1 dan seterusnya, capture bernama (?<nama>), serta grup tanpa capture (?:...).

Tanda kurung untuk pengelompokan#

Tanda kurung mengikat beberapa karakter menjadi satu kesatuan, sehingga metakarakter yang ditulis setelahnya menimpa keseluruhan kelompok, bukan satu karakter terakhir. Pada topik metakarakter, alternasi | terbukti berjangkauan sampai ujung pola dan menelan string anjing putih secara tak terduga. Tanda kurung memperbaiki hal itu, sebagaimana ditunjukkan skrip berikut:

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

my @jadwal = ("piket Senin", "piket Kamis", "piket Jumat", "latihan Senin");

foreach my $baris (@jadwal) {
    # tanda kurung membatasi jangkauan alternasi
    print "Cocok : $baris\n" if $baris =~ m/piket (Senin|Kamis)/;
}

# quantifier menimpah seluruh grup, bukan satu karakter
print "hahaha cocok\n" if "hahaha" =~ m/^(ha)+$/;
print "hahaha gagal pada ha+\n" unless "hahaha" =~ m/^ha+$/;
text Keluaran
Cocok : piket Senin
Cocok : piket Kamis
hahaha cocok
hahaha gagal pada ha+

Pola piket (Senin|Kamis) kini berarti piket Senin atau piket Kamis, sehingga latihan Senin tidak lagi lolos. Pada pengujian kedua, quantifier + ditempelkan pada grup (ha), sehingga hahaha dianggap sebagai ha yang berulang dan lolos. Tanpa tanda kurung, ha+ hanya mengulang huruf a, sehingga pola yang sama gagal. Kedua contoh itu menunjukkan bahwa tanda kurung mengubah makna pola, bukan sekadar menambah tanda baca.

Kebiasaan yang baik ketika menyusun pola adalah menulis kelompok utamanya terlebih dahulu, lalu mengujinya terhadap contoh positif dan contoh negatif. Skrip di atas sudah memuat keduanya, yaitu piket Senin sebagai contoh positif dan latihan Senin sebagai contoh negatif. Pola yang hanya diuji terhadap contoh positif sering lolos lebih longgar dari yang dimaksudkan, dan contoh negatif menangkap kelebihan itu sejak awal.

Capture bernomor pada $1 dan seterusnya#

Setiap tanda kurung yang berhasil mencocokkan teks menyimpan potongannya ke variabel bernomor, yaitu $1 untuk grup pertama, $2 untuk grup kedua, dan seterusnya. Variabel tersebut berlaku setelah pencocokan yang berhasil, sehingga potongan teks dapat dicetak, dihitung, atau disusun ulang. Skrip berikut memanfaatkan $1 dan $2 untuk menyalin isi jadwal:

perl capture-nomor.pl
#!/usr/bin/env perl
use strict;
use warnings;

my $baris = "Citra piket pada 2026-11-09";

if ($baris =~ m/(\w+) piket pada ([\d-]+)/) {
    print "Nama    : $1\n";
    print "Tanggal : $2\n";
}

# penomoran mengikuti tanda kurung pembuka dari kiri ke kanan
my $catatan = "nilai 90 dari skala 100";
if ($catatan =~ m/nilai (\d+) dari skala (\d+)/) {
    print "Skor  : $1\n";
    print "Skala : $2\n";
}

# grup bersarang ikut diberi nomor
my $piket = "piket tanggal 09 dan 16";
if ($piket =~ m/piket tanggal ((\d+)( dan \d+)*)/) {
    print "Keseluruhan  : $1\n";
    print "Tanggal awal : $2\n";
    print "Sisa pola    : $3\n";
}
text Keluaran
Nama    : Citra
Tanggal : 2026-11-09
Skor  : 90
Skala : 100
Keseluruhan  : 09 dan 16
Tanggal awal : 09
Sisa pola    :  dan 16

Penomoran mengikuti urutan tanda kurung pembuka dari kiri ke kanan, bukan urutan posisi dalam teks. Pada grup bersarang di bagian akhir, grup luar menangkap 09 dan 16 menjadi $1, grup dalamnya menangkap 09 menjadi $2, dan grup berikutnya menangkap dan 16 menjadi $3. Simbol \d dan \w di sini digunakan sebagai singkatan digit serta karakter kata, dan keduanya dibedah lebih rinci pada bagian kelas karakter.

Variabel $1 dan kawan-kawannya diisi oleh mesin pencocokan, lalu dapat digunakan persis seperti variabel biasa, termasuk di dalam string yang diinterpolasi. Isinya tetap tersimpan sampai pencocokan berhasil berikutnya menggantinya, sehingga kode di dalam blok if bekerja pada nilai terbaru. Bila jumlah grup bertambah banyak, capture bernama pada bagian berikutnya lebih aman daripada nomor yang terus bertambah.

Capture bernama (?)#

Capture bernama menuliskan nama di dalam grup dengan bentuk (?<nama>...), dan hasilnya dibaca melalui $+{nama} atau hash %+ yang memuat seluruh capture bernama. Nama membuat pola dan kode yang membacanya saling menjelaskan, karena $+{tanggal} jauh lebih mudah diurai daripada $2 pada pola yang panjang. Skrip berikut menulis ulang pencocokan sebelumnya dengan capture bernama:

perl capture-nama.pl
#!/usr/bin/env perl
use strict;
use warnings;

my $baris = "Dewi piket pada 2026-11-16";

if ($baris =~ m/(?<nama>\w+) piket pada (?<tanggal>[\d-]+)/) {
    print "Nama    : $+{nama}\n";
    print "Tanggal : $+{tanggal}\n";

    # hash %+ memuat seluruh capture bernama
    foreach my $kunci (sort keys %+) {
        print "$kunci = $+{$kunci}\n";
    }
}
text Keluaran
Nama    : Dewi
Tanggal : 2026-11-16
nama = Dewi
tanggal = 2026-11-16

Hash %+ berperilaku seperti hash biasa, sehingga kuncinya dapat dihitung, diurutkan, dan diulang seperti pada keluaran di atas. Hash itu hanya berisi capture yang benar-benar berhasil dicocokkan pada pencocokan terakhir.

Pola dengan capture bernama tetap mengisi $1 dan seterusnya seperti biasa, sehingga kedua gaya dapat digunakan bersama dalam satu program. Kombinasi nama dan nomor ini berguna saat pola lama dirawat, karena bagian yang sudah menggunakan nomor tidak perlu langsung ditulis ulang. Nama capture sendiri harus terdiri atas karakter identifier, sehingga huruf, angka, dan garis bawah menjadi pilihan yang aman.

Grup tanpa capture (?:…)#

Bukan semua tanda kurung dimaksudkan untuk menangkap teks. Bila pengelompokan hanya dibutuhkan untuk membatasi alternasi atau menampung quantifier, bentuk (?:...) mengelompokkan tanpa menambah nomor capture dan tanpa menggeser penomoran grup lain. Grup semacam ini membuat pola tetap terbaca tanpa menambah beban mengingat nomor capture, karena satu-satunya grup yang dihitung adalah grup yang memang dimaksudkan untuk menangkap. Skrip berikut menggunakan grup tanpa capture untuk memilih nomor ruang yang diizinkan:

perl tanpa-capture.pl
#!/usr/bin/env perl
use strict;
use warnings;

my @ruang = ("ruang 204", "ruang 205", "ruang 206", "laboratorium 204");

foreach my $b (@ruang) {
    # (?:...) mengelompokkan tanpa menambah nomor capture
    print "Cocok : $b\n" if $b =~ m/ruang (?:204|205)/;
}

my $data = "kode: CD-12";
if ($data =~ m/kode: ((?:AB|CD)-\d+)/) {
    # $1 tetap milik grup luar, grup dalam tidak menyusup
    print "Kode: $1\n";
}
text Keluaran
Cocok : ruang 204
Cocok : ruang 205
Kode: CD-12

Pada pola kedua, grup luar menangkap CD-12 menjadi $1, sedangkan grup (?:AB|CD) di dalamnya tidak menyimpan apa pun. Bila grup dalam ditulis biasa, $1 akan berisi CD dan $2 berisi CD-12, sehingga kode yang membacanya ikut berubah. Kebiasaan menggunakan (?:...) untuk pengelompokan murni menjaga penomoran tetap sesuai maksud penulisnya.

Selain menjaga penomoran, grup tanpa capture sedikit mengurangi pekerjaan mesin pencocokan karena hasilnya tidak perlu disimpan. Efeknya kecil pada pola pendek, tetapi kebiasaan ini menjaga kode tetap bermakna, yaitu setiap tanda kurung biasa benar-benar berarti nilai yang ingin diambil. Bila keseluruhan pola sudah menggunakan capture bernama, grup (?:...) tetap berguna untuk alternasi di dalam nilai yang ditangkap.

Kesalahan umum#

Kesalahan pertama adalah membaca $1 setelah pencocokan gagal. Variabel bernomor tidak dikosongkan oleh kegagalan, melainkan masih memuat hasil pencocokan yang berhasil sebelumnya. Gejalanya sulit dilacak, karena program tidak berhenti dan tidak menampilkan error, tetapi datanya salah. Perbaikannya adalah mengambil $1 dan kawan-kawannya hanya di dalam blok if yang menguji keberhasilan pencocokan itu sendiri.

Kesalahan kedua adalah menganggap $1 berlaku setelah pola disunting. Penambahan satu tanda kurung untuk keperluan pengelompokan menggeser seluruh nomor di belakangnya, sehingga $2 tiba-tiba memuat teks yang berbeda. Uji kecil dengan print setelah setiap perubahan pola menangkap pergeseran nomor ini sebelum data salah disimpan. Perbaikannya adalah menggunakan grup (?:...) untuk pengelompokan murni dan capture bernama untuk nilai yang ditangkap, sehingga penyuntingan pola tidak mengubah arti variabel penangkapnya.

Ringkasan#

  • Tanda kurung mengelompokkan bagian pola, sehingga alternasi dibatasi jangkauannya dan quantifier menimpa seluruh kelompok.
  • Setiap grup yang cocok menyimpan teksnya ke $1, $2, dan seterusnya menurut urutan tanda kurung pembuka, termasuk grup bersarang.
  • Capture bernama (?<nama>...) dibaca melalui $+{nama} atau hash %+ dan tahan terhadap penyuntingan pola.
  • Bentuk (?:...) mengelompokkan tanpa menangkap, sehingga penomoran capture lain tidak bergeser.
  • $1 dan kawan-kawannya hanya sah dibaca setelah pencocokan yang berhasil, karena nilai lama tidak dikosongkan oleh kegagalan.

Referensi#