Ekspresi Reguler

preg_match, preg_replace, dan aturan delimiter PCRE.

Daftar isi

Ekspresi reguler (regular expression) adalah pola teks yang mendeskripsikan bentuk string tertentu, misalnya format kode pendaftaran atau urutan tanggal. PHP menyediakan keluarga fungsi PCRE (Perl Compatible Regular Expressions) untuk mencocokkan, mengambil, dan mengganti teks menurut pola. Topik ini membahas aturan delimiter yang wajib dipatuhi setiap pola, fungsi preg_match untuk pencocokan, preg_match_all untuk pengambilan seluruh kemunculan, dan preg_replace untuk penggantian berbasis pola. Setelah menyelesaikan topik ini, pola sederhana dapat dibaca, ditulis, dan diuji dengan keluaran yang pasti.

Delimiter dan anatomi pola#

Setiap pola PCRE ditulis sebagai string yang dibingkai oleh sepasang delimiter, yaitu karakter pembatas yang sama di awal dan di akhir pola. Delimiter boleh berupa karakter apa pun yang bukan huruf, angka, garis miring terbalik, maupun spasi, tetapi yang paling umum adalah garis miring /, tanda pagar #, dan tanda gelombang ~. Karakter yang sama dengan delimiter tidak boleh muncul di dalam pola tanpa diawali garis miring terbalik, sehingga pola yang memuat banyak garis miring lebih nyaman ditulis dengan delimiter tanda pagar. Sesudah delimiter penutup, satu atau beberapa modifier dapat ditambahkan, misalnya i agar pencocokan tidak peka huruf besar dan kecil.

php
<?php

$tanggal = "Acara dimulai 15/03/2026.";

echo preg_match('/\d{2}\/\d{2}\/\d{4}/', $tanggal) . PHP_EOL;
echo preg_match('#\d{2}/\d{2}/\d{4}#', $tanggal) . PHP_EOL;
echo preg_match('/acara/i', $tanggal) . PHP_EOL;
text Keluaran
1
1
1

Ketiga pencocokan menghasilkan 1 karena polanya menemukan kecocokan. Pada baris pertama, delimiter garis miring memaksa setiap garis miring di dalam pola ditulis sebagai \/. Baris kedua memakai delimiter tanda pagar sehingga garis miring pada 15/03/2026 ditulis apa adanya. Baris ketiga menunjukkan peran modifier i, karena kata acara huruf kecil berhasil mencocokkan Acara di awal kalimat.

Mencocokkan dengan preg_match#

Fungsi preg_match mencari kecocokan pertama sebuah pola pada string. Nilai kembaliannya adalah 1 apabila kecocokan ditemukan, 0 apabila tidak ada, dan false apabila polanya gagal dikompilasi. Parameter ketiga yang bersifat opsional menerima array yang diisi hasil pencocokan. Elemen 0 berisi seluruh teks yang cocok, sedangkan elemen berikutnya berisi isi setiap kelompok tangkap (capture group). Kelompok tangkap adalah bagian pola yang dibungkus sepasang tanda kurung biasa.

php
<?php

$kode = "LOMBA-2026-042";

$jumlah = preg_match('/^LOMBA-(\d{4})-(\d{3})$/', $kode, $m);
echo $jumlah . PHP_EOL;
echo $m[0] . PHP_EOL;
echo $m[1] . PHP_EOL;
echo $m[2] . PHP_EOL;

$tidakCocok = preg_match('/^LOMBA-(\d{4})-(\d{3})$/', "LOMBA-26-42", $m2);
echo $tidakCocok . PHP_EOL;
text Keluaran
1
LOMBA-2026-042
2026
042
0

Pola di atas dibaca sebagai berikut. Tanda ^ menuntut pencocokan dimulai dari awal string, teks LOMBA- dicocokkan apa adanya, \d{4} menuntut tepat empat digit, dan $ menuntut pencocokan berakhir di akhir string. Dua pasang tanda kurung menangkap empat digit tahun dan tiga digit nomor urut ke dalam $m[1] dan $m[2], sedangkan $m[0] memuat seluruh kecocokan. Pemanggilan terakhir menghasilkan 0 karena tahun dua digit tidak memenuhi syarat empat digit.

Array hasil dibiarkan kosong apabila tidak ada kecocokan, sehingga elemennya baru dibaca setelah nilai kembalian diperiksa. Pembandingan !== 1 memisahkan ketiga kemungkinan nilai kembalian sekaligus, yaitu kecocokan ditemukan, tidak ditemukan, dan pola yang gagal dikompilasi.

Mengambil semua kemunculan dengan preg_match_all#

Fungsi preg_match berhenti pada kecocokan pertama, sehingga pencarian seluruh kemunculan memerlukan preg_match_all. Fungsi ini mengembalikan jumlah kecocokan yang ditemukan dan mengisi array hasil dengan setiap kecocokan pada elemen 0. Bentuk penggunaannya sama dengan preg_match, sehingga keduanya dapat dipertukarkan dengan mudah sesuai kebutuhan.

php
<?php

$catatan = "Gedung 3 lantai 2 ruang 105";

preg_match('/\d+/', $catatan, $pertama);
echo $pertama[0] . PHP_EOL;

preg_match_all('/\d+/', $catatan, $semua);
echo implode(",", $semua[0]) . PHP_EOL;
text Keluaran
3
3,2,105

Pola \d+ berarti satu digit atau lebih. Pemanggilan preg_match menghentikan pencarian setelah menemukan angka 3 pada kata Gedung, sedangkan preg_match_all melanjutkan sampai akhir string sehingga ketiga angka terkumpul pada $semua[0]. Pemanggilan implode kemudian menggabungkan angka-angka tersebut menjadi satu baris agar mudah dibaca.

Nilai kembalian preg_match_all adalah jumlah kecocokan yang ditemukan, sehingga hasil nol dapat diperiksa tanpa membaca arraynya. Elemen 0 menyimpan seluruh kecocokan berurutan sesuai posisinya dalam string, sedangkan elemen berikutnya menyimpan isi kelompok tangkap yang disusun per kelompok. Pola tanpa kelompok tangkap cukup dibaca dari elemen 0 saja.

Mengganti teks menurut pola dengan preg_replace#

Fungsi preg_replace menggantikan setiap bagian string yang cocok dengan pola tertentu. Nilai penggantinya boleh memuat rujukan balik (backreference) berbentuk $1, $2, dan seterusnya, yang menunjuk isi kelompok tangkap dari pola. Kemampuan ini memungkinkan penataan ulang teks, misalnya mengubah urutan tanggal, tanpa memecah string secara manual.

php
<?php

$pengumuman = "Acara dimulai 15/03/2026, daftar ulang 20/03/2026.";

echo preg_replace('/(\d{2})\/(\d{2})\/(\d{4})/', '$3-$2-$1', $pengumuman) . PHP_EOL;
echo preg_replace('/\s+/', ' ', "Spasi    ganda   dirapikan") . PHP_EOL;
text Keluaran
Acara dimulai 2026-03-15, daftar ulang 2026-03-20.
Spasi ganda dirapikan

Pada baris pertama, tiga kelompok tangkap menyimpan tanggal, bulan, dan tahun, kemudian rujukan $3-$2-$1 menyusun ulang ketiganya menjadi format tahun-bulan-hari. Kedua tanggal dalam kalimat ikut tergantikan karena preg_replace memproses seluruh kemunculan. Baris kedua memanfaatkan \s+, yaitu satu atau lebih karakter spasi, untuk merapikan spasi ganda menjadi satu spasi.

Pola dengan kelompok tangkap bernama lebih mudah dibaca saat polanya panjang. Nama kelompok ditulis dengan bentuk (?<nama>...) dan hasilnya dibaca melalui kunci array dengan nama yang sama, sebagaimana ditunjukkan berikut ini.

php kode-lomba.php
<?php

function bacaKodeLomba(string $kode): void
{
    if (preg_match('/^LOMBA-(?<tahun>\d{4})-(?<nomor>\d{3})$/', $kode, $m) !== 1) {
        echo $kode . ": format tidak sesuai" . PHP_EOL;
        return;
    }

    echo $kode . ": tahun " . $m['tahun'] . ", nomor urut " . $m['nomor'] . PHP_EOL;
}

bacaKodeLomba("LOMBA-2026-042");
bacaKodeLomba("LOMBA-26-42");
bacaKodeLomba("lomba-2026-042");
text Keluaran
LOMBA-2026-042: tahun 2026, nomor urut 042
LOMBA-26-42: format tidak sesuai
lomba-2026-042: format tidak sesuai

Pembandingan !== 1 mengelompokkan dua kemungkinan kegagalan sekaligus, yaitu tidak ada kecocokan dan pola yang gagal dikompilasi. Kode lomba dengan tahun dua digit dan kode yang ditulis huruf kecil sama-sama ditolak karena tidak memenuhi pola, sedangkan kode yang sesuai menghasilkan rincian tahun dan nomor urut melalui kunci tahun dan nomor.

Kesalahan umum#

Empat kesalahan berikut paling sering muncul saat menulis pola PCRE.

  • Delimiter pembuka tidak ditutup atau karakter delimiter muncul di dalam pola tanpa pelolosan. Pola gagal dikompilasi, fungsi mengembalikan false, dan PHP menampilkan pesan warning yang menyebut posisi kesalahannya. Perbaikannya adalah memastikan sepasang delimiter sama dan memilih delimiter yang tidak muncul dalam pola.
  • preg_match dianggap menemukan seluruh kemunculan pola. Fungsi tersebut berhenti pada kecocokan pertama, sehingga pencarian terasa tidak lengkap. Perbaikannya adalah menggunakan preg_match_all apabila semua kemunculan diperlukan.
  • preg_replace dipakai untuk penggantian teks tetap yang tidak memuat unsur pola sama sekali. Pemakaian ini berfungsi tetapi menambah beban kompilasi pola yang tidak perlu. Perbaikannya adalah menggunakan str_replace untuk penggantian teks biasa.
  • Pola untuk teks UTF-8 ditulis tanpa modifier u, sehingga kuantifier dan kelas karakter menghitung byte dan bukan karakter. Pola sederhana sering tetap berjalan benar, sedangkan pola yang menyentuh huruf non-ASCII meleset tanpa pesan. Perbaikannya adalah menambahkan modifier u pada akhir pola yang memproses teks berpenyandian UTF-8.

Ringkasan#

  • Setiap pola PCRE dibingkai sepasang delimiter yang sama, dan karakter delimiter tidak boleh muncul di dalam pola tanpa pelolosan, sedangkan modifier seperti i mengubah perilaku pencocokan.
  • preg_match mengembalikan 1, 0, atau false serta mengisi array hasil yang memuat kecocokan penuh dan isi setiap kelompok tangkap.
  • preg_match_all mengumpulkan seluruh kemunculan pola, sedangkan preg_replace menggantikannya dan mendukung rujukan balik $1 sampai $n untuk menata ulang teks.
  • Kelompok tangkap bernama berbentuk (?<nama>...) menghasilkan array hasil yang dibaca melalui kunci nama sehingga pola panjang tetap mudah diikuti.

Referensi#