Apa itu Quantifier?
Quantifier menentukan berapa kali karakter atau grup sebelumnya harus muncul agar cocok. Tanpa quantifier, setiap elemen regex cocok tepat satu kali.
Quantifier Dasar
| Quantifier | Arti | Contoh |
|---|---|---|
* |
0 atau lebih | ab*c cocok "ac", "abc", "abbc" |
+ |
1 atau lebih | ab+c cocok "abc", "abbc" (bukan "ac") |
? |
0 atau 1 (opsional) | colou?r cocok "color", "colour" |
{n} |
Tepat n kali | a{3} cocok "aaa" |
{n,} |
Minimal n kali | a{2,} cocok "aa", "aaa", "aaaa"... |
{n,m} |
Antara n dan m kali | a{2,4} cocok "aa", "aaa", "aaaa" |
Contoh Penggunaan
// * (nol atau lebih)
/go*gle/.test("ggle"); // true (0 huruf "o")
/go*gle/.test("google"); // true (2 huruf "o")
/go*gle/.test("gooogle"); // true (3 huruf "o")
// + (satu atau lebih)
/go+gle/.test("ggle"); // false (butuh minimal 1 "o")
/go+gle/.test("google"); // true
// ? (opsional)
/https?:/.test("http:"); // true
/https?:/.test("https:"); // true
// {n} (tepat n kali)
/\d{4}/.test("2024"); // true
/\d{4}/.test("123"); // false (hanya 3 digit)
// {n,m} (range)
/\d{2,4}/.test("1"); // false
/\d{2,4}/.test("12"); // true
/\d{2,4}/.test("12345"); // true (cocok "1234" di awal)
Greedy vs Lazy
Secara default, quantifier bersifat greedy — mereka mencocokkan sebanyak mungkin karakter. Tambahkan ? setelah quantifier untuk membuatnya lazy (mencocokkan sesedikit mungkin).
const html = "<b>tebal</b> dan <i>miring</i>";
// Greedy: .* mengambil sebanyak mungkin
html.match(/<.+>/); // ["<b>tebal</b> dan <i>miring</i>"]
// Lazy: .+? mengambil sesedikit mungkin
html.match(/<.+?>/); // ["<b>"]
// Semua tag dengan lazy + global
html.match(/<.+?>/g); // ["<b>", "</b>", "<i>", "</i>"]
Ini sangat penting saat parsing HTML atau teks yang punya delimiter berulang!
Quantifier pada Character Class dan Grup
Quantifier berlaku untuk elemen tepat di depannya:
// Quantifier pada karakter tunggal
/ab+/; // "a" diikuti 1+ huruf "b"
// Quantifier pada character class
/[0-9]+/; // 1+ digit berturut-turut
// Quantifier pada group
/(ha)+/; // 1+ pengulangan "ha"
"hahaha".match(/(ha)+/); // ["hahaha"]
Contoh Praktis
// Validasi nomor telepon Indonesia (08xx-xxxx-xxxx)
const phoneRegex = /^08\d{2}-?\d{4}-?\d{4}$/;
console.log(phoneRegex.test("0812-3456-7890")); // true
console.log(phoneRegex.test("081234567890")); // true
// Cari kata yang panjangnya 5-8 huruf
const kata = "aku suka belajar programming dan coding";
console.log(kata.match(/\b[a-zA-Z]{5,8}\b/g));
// ["belajar", "coding"]
// Parsing angka dengan optional desimal
const angkaRegex = /\d+\.?\d*/g;
console.log("harga 99.9 dan 100".match(angkaRegex));
// ["99.9", "100"]
🎭 Analogi sehari-hari: Quantifier = aturan jumlah cabang. * = "minimal 0 cabang OK" (boleh kosong). + = "minimal 1 cabang wajib". ? = "0 atau 1 cabang, opsional". {2,5} = "antara 2 sampai 5 cabang". Greedy = pohon ambil cabang sebanyak mungkin. Lazy = pohon ambil cabang sesedikit mungkin.
💡 Greedy vs Lazy critical untuk parsing: Default greedy = <.+> di <b>tebal</b> ambil semua dari <b> sampai </b> (gak match per tag). Lazy <.+?> ambil sesedikit mungkin = match per tag. Untuk parse delimited content (HTML tag, string quotes), lazy hampir selalu yang dibutuhkan.
⚠️ Jebakan klasik:
- Greedy lupa pakai lazy = parse HTML/JSON salah hasil
a*match empty string —/a*/.exec("xxx")=[""]. Pakai+kalau butuh minimal 1{n,}lupa koma —{n}= exact,{n,}= minimal n. Beda makna- Catastrophic backtracking dengan nested quantifiers —
(a+)+di string panjang = ReDoS - Quantifier setelah anchor —
^*invalid, anchor bukan target quantify
🎯 Pattern umum:
- Optional protocol:
https?:// - Phone digits:
\d{3,4}atau\d{3}-\d{4} - Lazy capture:
<(.+?)>untuk per-tag - Email local:
[\w.-]+ - Tahun 4-digit:
\d{4}
TL;DR: Quantifier = berapa kali repeat. * (0+), + (1+), ? (0/1), {n,m} (range). Default greedy ambil maksimal — pakai ? jadikan lazy untuk parse delimited content. Awas catastrophic backtracking dengan nested quantifier.