Lewati ke konten
Toova
Semua Alat

10 Trik Regex yang Wajib Diketahui Setiap Developer

Toova

Ekspresi reguler adalah salah satu alat yang awalnya terasa sulit ditembus, lalu tiba-tiba terasa pas di tempatnya. Begitu Anda memahaminya, Anda mulai melihatnya di mana-mana: validasi input, parsing log, pipeline cari-dan-ganti, perutean URL. Namun sebagian besar developer hanya menggunakan beberapa fitur saja — kelas karakter, kuantifier, anchor — dan membiarkan sisa spesifikasinya tak tersentuh.

Panduan ini membahas sepuluh fitur regex yang melampaui dasar-dasar. Setiap fitur memecahkan masalah nyata yang tidak dapat ditangani dengan rapi oleh pola yang lebih sederhana. Semua contoh menggunakan sintaks JavaScript, yang juga valid untuk lingkungan apa pun yang kompatibel dengan ECMAScript.

Anda dapat menguji setiap pola di artikel ini menggunakan Toova Regex Tester tanpa menulis satu baris kode pengaturan pun.

1. Lookahead: Cocokkan Tanpa Mengonsumsi

Lookahead menegaskan bahwa suatu pola harus (atau tidak boleh) mengikuti posisi saat ini, tanpa membuat mesin pencocokan melewati karakter-karakter tersebut. Teks yang dicocokkan tidak menyertakan apa yang diperiksa lookahead.

Sintaks lookahead positif: (?=...)

// Lookahead positif: cocokkan "foo" hanya saat diikuti "bar"
const re1 = /foo(?=bar)/;
re1.test('foobar'); // true
re1.test('foobaz'); // false

Sintaks lookahead negatif: (?!...)

// Lookahead negatif: cocokkan "foo" yang TIDAK diikuti "bar"
const re2 = /foo(?!bar)/;
re2.test('foobaz'); // true
re2.test('foobar'); // false

Penggunaan praktis: cocokkan angka harga hanya saat diikuti oleh simbol mata uang, tanpa menyertakan simbol tersebut dalam nilai yang ditangkap. Atau validasi bahwa kata sandi berisi setidaknya satu angka menggunakan (?=.*\d) tanpa menentukan di mana angka itu harus muncul.

Lookahead memiliki lebar nol — mereka tidak mengonsumsi karakter. Anda dapat menumpuk beberapa lookahead pada posisi yang sama untuk menerapkan beberapa kondisi independen secara bersamaan.

2. Lookbehind: Periksa Apa yang Datang Sebelumnya

Lookbehind adalah cermin dari lookahead: lookbehind memeriksa teks yang mendahului posisi saat ini tanpa memasukkannya ke dalam hasil cocok.

Sintaks lookbehind positif: (?<=...)

// Lookbehind positif: cocokkan "bar" hanya saat didahului "foo"
const re3 = /(?<=foo)bar/;
re3.test('foobar'); // true
re3.test('bazbar'); // false

Sintaks lookbehind negatif: (?<!...)

// Lookbehind negatif: cocokkan "bar" yang TIDAK didahului "foo"
const re4 = /(?<!foo)bar/;
re4.test('bazbar'); // true
re4.test('foobar'); // false

Lookbehind muncul di ECMAScript 2018 dan didukung di semua peramban modern serta Node.js 10+. Kasus penggunaan umum: ekstrak bagian nilai dari pasangan kunci-nilai seperti name=Alice dengan mencocokkan semua yang ada setelah name= tanpa memasukkan kunci ke dalam hasil cocok.

Catatan: tidak seperti lookahead, ekspresi lookbehind di JavaScript tidak boleh berisi pola dengan panjang variabel — ekspresi lookbehind harus memiliki panjang maksimum yang tetap atau terbatas.

3. Named Capture Group: Pola yang Mendokumentasi Diri

Grup tangkapan standar direferensikan dengan nomor: $1, $2, dan seterusnya. Saat Anda menambah atau menghapus grup, setiap referensi di hilir akan rusak. Grup bernama mengatasi hal ini dengan memungkinkan Anda melampirkan label pada setiap grup.

const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const m = '2026-05-10'.match(dateRe);
console.log(m.groups.year);  // "2026"
console.log(m.groups.month); // "05"
console.log(m.groups.day);   // "10"

Grup bernama juga tersedia dalam string penggantian melalui $<name>:

// Referensi balik menggunakan grup bernama dalam pola
const quoteRe = /(?<q>['"]).*?\k<q>/;
quoteRe.test('"hello"'); // true
quoteRe.test('"hello''); // false

Nama grup harus berupa pengidentifikasi JavaScript yang valid. Gunakan nama deskriptif yang mencerminkan apa yang ditangkap grup — year, port, protocol — dan pola Anda menjadi hampir mendokumentasi diri sendiri. Anda juga dapat menggunakan \k<name> di dalam pola itu sendiri untuk mereferensikan balik grup bernama, seperti ditunjukkan di atas.

4. Kuantifier Non-Greedy: Cocokkan Seminimum Mungkin

Secara default, kuantifier (*, +, ?) bersifat greedy — mereka mencocokkan sebanyak mungkin karakter. Menambahkan ? setelah kuantifier membuatnya non-greedy (juga disebut lazy atau reluctant), mencocokkan sesedikit mungkin karakter.

const html = '<a>click</a>';

// Greedy (default) — cocokkan string terpanjang yang mungkin
/<.+>/.exec(html)?.[0]; // '<a>click</a>'

// Non-greedy — cocokkan string terpendek yang mungkin
/<.+?>/.exec(html)?.[0]; // '<a>'

Hal ini penting saat mem-parsing HTML, XML, atau format apa pun di mana pembatas yang sama dapat muncul beberapa kali. Versi greedy menelan semuanya dari tag pembuka pertama hingga tag penutup terakhir di seluruh string. Versi non-greedy berhenti pada cocok penutup pertama yang valid.

Hal yang sama berlaku untuk +? (satu atau lebih, lazy) dan ?? (nol atau satu, lazy). Kuantifier non-greedy tidak mengubah apa yang bisa dicocokkan — mereka mengubah cocok valid mana yang dipilih saat ada beberapa opsi.

5. Menghindari Catastrophic Backtracking

Backtracking adalah cara mesin regex pulih dari upaya pencocokan yang gagal — mereka mencoba jalur berbeda melalui pola. Dalam sebagian besar kasus, ini tidak terlihat dan cepat. Tetapi pola tertentu dapat menyebabkan mesin menjelajahi jumlah jalur yang tumbuh secara eksponensial, membuat proses Node.js bertekuk lutut bahkan untuk string input yang sederhana.

Pola berbahaya klasik adalah kuantifier bertingkat seperti (a+)+ yang diterapkan pada string seperti aaaaab. Mesin mencoba setiap cara yang mungkin untuk membagi karakter a di antara grup dalam dan luar sebelum menyimpulkan bahwa tidak ada cocok.

Atomic group ((?>...)) mencegah hal ini dengan memberi tahu mesin untuk tidak melakukan backtrack ke grup setelah grup itu cocok. JavaScript tidak mendukung atomic group secara native, tetapi Anda dapat mengemulasi perilaku possessive dengan lookahead:

// Tanpa atomic group — mesin melakukan backtrack ke (\d+)
// Dengan atomic group — setelah (\d+) cocok, backtracking tidak diizinkan
// JavaScript tidak mendukung atomic group secara native,
// tetapi Anda dapat mengemulasinya dengan trik lookahead:
const re5 = /(?=(\d+))\1(?!\d)/; // emulasi possessive \d++

Aturan praktis yang lebih aman: hindari kuantifier yang langsung bersarang di dalam kuantifier lain kecuali Anda memiliki alasan spesifik. Tulis ulang pola untuk lebih tepat tentang apa yang dicocokkan. Anda juga dapat menggunakan alat Text Diff untuk membandingkan output dari dua pola setara secara berdampingan saat Anda merefaktor.

6. Operasi Himpunan Kelas Karakter (Flag Unicode v)

ECMAScript 2024 memperkenalkan flag v, yang mengaktifkan operasi himpunan di dalam kelas karakter. Ini memungkinkan Anda mengekspresikan "semua huruf kecuali vokal" atau "huruf kapital yang juga ASCII" sebagai definisi kelas yang bersih alih-alih alternasi yang berbelit-belit.

// Pengurangan kelas karakter POSIX tidak ada di JS,
// tetapi mode Unicode sets (flag `v`) menambahkan operasi himpunan:
const lettersNoVowels = /[a-z--[aeiou]]/v;
lettersNoVowels.test('b'); // true
lettersNoVowels.test('e'); // false

Flag v mendukung tiga operasi di dalam kelas karakter:

  • Subtraction: [A--B] — karakter di A tetapi tidak di B
  • Intersection: [A&&B] — karakter di A dan B
  • Union: [AB] — karakter di A atau B (sama seperti kelas karakter standar)

Node.js 20+ dan semua peramban evergreen mendukung flag v. Flag ini adalah superset dari flag u — jangan menggabungkan keduanya; gunakan v saja saat Anda memerlukan fiturnya.

7. Batas Kata: Pencocokan Kata Utuh

Anchor \b mencocokkan posisi antara karakter kata (\w) dan karakter non-kata. Ia tidak mengonsumsi karakter — ia hanya menegaskan posisi. Kebalikannya \B mencocokkan posisi apa pun yang bukan batas kata.

const sentence = 'cat concatenate';

// Tanpa \b — "cat" juga ditemukan di dalam "concatenate"
/cat/g.exec(sentence); // cocokkan "cat" di "cat" DAN di "concatenate"

// Dengan \b — hanya kata utuh "cat"
/\bcat\b/g.exec(sentence); // cocokkan hanya "cat" yang berdiri sendiri
// \B adalah kebalikannya: cocokkan di dalam kata, bukan di batas
/\Bcat\B/.test('concatenate'); // true — "cat" ada di dalam kata

Batas kata sangat penting saat mencari pengidentifikasi di kode atau prosa. Tanpa batas kata, pencarian variabel bernama id juga akan mengenai indexOf, invalid, dan grid. Gunakan \bterm\b untuk membatasi cocok pada kemunculan yang berdiri sendiri.

Satu peringatan penting: \b menggunakan definisi JavaScript tentang karakter kata ([a-zA-Z0-9_]). Karakter beraksen dan huruf non-Latin diperlakukan sebagai karakter non-kata. Untuk batas kata yang sadar Unicode, gabungkan flag v dengan kelas properti Unicode.

8. Mode Multiline: Anchor Per Baris

Secara default, ^ hanya cocok dengan awal string dan $ hanya cocok dengan akhir string. Flag m (multiline) mengubah hal ini: ^ cocok dengan awal setiap baris dan $ cocok dengan akhir setiap baris.

const text = 'line one\nline two\nline three';

// Tanpa flag m — ^ hanya cocok dengan awal seluruh string
/^line/.test(text); // true (hanya baris pertama)

// Dengan flag m — ^ cocok dengan awal SETIAP baris
const matches = text.match(/^line/gm);
console.log(matches); // ['line', 'line', 'line']

Hal ini sangat diperlukan saat memproses teks multi-baris seperti file log, file konfigurasi, atau kode. Penggunaan umum termasuk mengekstrak baris yang dimulai dengan kata kunci, mengganti token akhir baris, atau memvalidasi bahwa setiap baris dalam blok cocok dengan suatu pola.

Jangan bingungkan flag m dengan flag s (dotAll). Flag s membuat . juga mencocokkan karakter baris baru. Flag m tidak memengaruhi . sama sekali — hanya perilaku ^ dan $.

9. Unicode Property Escape: Pencocokan Karakter Internasional

Flag u mengaktifkan Unicode property escape, yang memungkinkan Anda mencocokkan karakter berdasarkan kategori Unicode, aksara, atau properti lainnya. Ini adalah cara yang benar untuk mencocokkan huruf, angka, atau tanda baca di semua sistem penulisan manusia — bukan hanya ASCII.

// Flag u mengaktifkan Unicode property escape
const letters = /\p{L}+/u;
letters.test('Héllo');   // true
letters.test('你好');    // true
letters.test('12345');   // false

// Cocokkan hanya huruf kapital di seluruh aksara
const upper = /\p{Lu}+/u;
upper.test('ABC');  // true
upper.test('abc');  // false
// Cocokkan emoji (kategori umum Unicode: Symbol, Other)
const emoji = /\p{So}/u;
emoji.test('🚀'); // true

Properti Unicode yang paling umum digunakan adalah:

  • \p{L} — huruf apa pun (semua aksara)
  • \p{Lu} — huruf kapital
  • \p{Ll} — huruf kecil
  • \p{N} — angka apa pun
  • \p{Nd} — digit desimal
  • \p{P} — tanda baca
  • \p{Script=Latin} — karakter aksara Latin
  • \p{Emoji} — karakter emoji

Gunakan \P{...} (P kapital) untuk menegasi — mencocokkan semua yang tidak memiliki properti yang ditentukan. Daftar lengkap properti Unicode yang didukung beserta nilainya dipelihara dalam dokumentasi MDN.

10. Pola Verbose melalui Perakitan String

Banyak varian regex (Python, Ruby, .NET, PCRE) mendukung mode verbose atau extended (flag x) yang memungkinkan spasi dan komentar di dalam pola. JavaScript tidak memiliki flag ini — flag x tidak valid di ECMAScript.

Solusi standarnya adalah merakit pola dari konstanta string bernama dan menggabungkannya dengan new RegExp():

// JavaScript tidak memiliki flag x native,
// tetapi Anda dapat membangun pola yang mudah dibaca sebagai konstanta string:
const YEAR  = '(?<year>\\d{4})';
const SEP   = '-';
const MONTH = '(?<month>\\d{2})';
const DAY   = '(?<day>\\d{2})';
const datePattern = new RegExp(YEAR + SEP + MONTH + SEP + DAY);

Setiap konstanta menggambarkan apa yang dicocokkannya, dan pola akhir terbaca seperti sebuah kalimat. Pendekatan ini juga memudahkan untuk mengomposisi sub-pola bersama di beberapa definisi regex dalam basis kode, dan untuk menguji unit setiap komponen secara independen.

Untuk pola yang kurang kompleks, menyimpan seluruh regex pada satu baris dengan komentar inline di blok komentar terdekat seringkali cukup. Tujuannya adalah memastikan bahwa developer berikutnya (termasuk Anda di masa depan) dapat memahami pola tanpa menjalankannya melalui decoder.

Menyatukan Semuanya

Sepuluh teknik ini mencakup sebagian besar area "mengapa regex ini gagal pada edge case?". Lookahead dan lookbehind memungkinkan Anda menegaskan konteks tanpa mengonsumsinya. Grup bernama menjaga pola tetap mudah dibaca di tengah refaktorisasi. Kuantifier non-greedy mencegah over-matching yang tidak disengaja. Unicode property escape menangani input yang melampaui ASCII.

Cara terbaik untuk membangun kefasihan adalah bereksperimen dengan pola nyata terhadap data nyata. Gunakan Regex Tester untuk beriterasi dengan cepat. Saat pola Anda menghasilkan output yang perlu dibandingkan atau dibersihkan, alat Text Diff menunjukkan tepat apa yang berubah antar percobaan. Dan jika regex Anda mem-parsing JSON, JSON Formatter memungkinkan Anda memeriksa hasil terstruktur tanpa meninggalkan peramban.

Untuk referensi komprehensif semua sintaks dan flag regex JavaScript, MDN Regex Cheatsheet adalah halaman tunggal terbaik untuk ditandai. Untuk debugging pola interaktif dengan visualisasi cocok penuh, regex101.com mendukung mode JavaScript dengan penjelasan bawaan untuk setiap komponen dalam pola.