Alternation & Lookahead — Regex

Alternation (Atau) Operator pipe | berfungsi sebagai "atau" di regex. Pattern di kiri ATAU kanan harus cocok: /kucing|anjing/.test("Saya punya kucing"); // true

Alternation (Atau)

Operator pipe | berfungsi sebagai "atau" di regex. Pattern di kiri ATAU kanan harus cocok:

/kucing|anjing/.test("Saya punya kucing");  // true
/kucing|anjing/.test("Saya punya anjing");  // true
/kucing|anjing/.test("Saya punya ikan");    // false

Alternation dalam Group

Tanpa group, | memisahkan seluruh pattern. Gunakan group untuk membatasi scope alternation:

// TANPA group: "saya kucing" ATAU "anjing"
/saya kucing|anjing/.test("anjing");  // true (bukan yang diinginkan)

// DENGAN group: "saya" diikuti "kucing" ATAU "anjing"
/saya (kucing|anjing)/.test("anjing");       // false ✓
/saya (kucing|anjing)/.test("saya anjing");  // true ✓

Bisa juga lebih dari dua pilihan:

/\.(jpg|jpeg|png|gif|webp)$/i.test("foto.PNG");  // true
/\.(jpg|jpeg|png|gif|webp)$/i.test("doc.pdf");   // false

Lookahead

Lookahead memeriksa apakah suatu pattern ada di depan posisi saat ini, tanpa mengonsumsi (memasukkan) karakter tersebut ke dalam kecocokan.

Positive Lookahead (?=...)

Cocok jika pattern di depan ada:

// Temukan angka yang diikuti "px"
"width: 100px, height: 200em".match(/\d+(?=px)/g);
// ["100"] — hanya 100 yang diikuti "px"

// Harga yang diikuti "rb"
"50rb dan 100rb".match(/\d+(?=rb)/g);
// ["50", "100"]

Perhatikan bahwa "px" dan "rb" tidak termasuk dalam hasil match.

Negative Lookahead (?!...)

Cocok jika pattern di depan TIDAK ada:

// Angka yang TIDAK diikuti "px"
"100px 200em 300".match(/\d+(?!px)/g);
// ["10", "200", "300"] — (10 karena "100" split)

// Lebih presisi dengan word boundary:
"100px 200em 300".match(/\b\d+(?!px)\b/g);
// ["200", "300"]

Lookbehind

Lookbehind memeriksa apa yang ada di belakang posisi saat ini.

Positive Lookbehind (?<=...)

// Angka yang didahului "
quot; "$100 dan 200 dan $300".match(/(?<=\$)\d+/g); // ["100", "300"] // Teks setelah "nama: " "nama: Budi".match(/(?<=nama: )\w+/); // ["Budi"]

Negative Lookbehind (?<!...)

// Angka yang TIDAK didahului "
quot; "$100 dan 200 dan $300".match(/(?<!\$)\b\d+/g); // ["200"]

Kombinasi Lookahead

Lookahead sering digunakan untuk validasi password yang membutuhkan beberapa syarat sekaligus:

// Password harus mengandung:
// - Minimal 8 karakter
// - Minimal 1 huruf besar
// - Minimal 1 angka
// - Minimal 1 karakter spesial
const passwordRegex = /^(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*]).{8,}$/;

passwordRegex.test("abc12345");     // false (tidak ada huruf besar)
passwordRegex.test("Abc12345");     // false (tidak ada special char)
passwordRegex.test("Abc1234!");     // true ✓

Setiap (?=...) adalah syarat terpisah yang harus dipenuhi, dan semuanya diperiksa dari posisi yang sama (awal string karena ada ^).

Contoh Praktis

// Format angka dengan pemisah ribuan
const formatRibuan = (n) =>
  String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ".");
console.log(formatRibuan(1234567)); // "1.234.567"

// Temukan method yang diikuti tanda kurung
const code = "getData() saveData() count";
console.log(code.match(/\w+(?=\(\))/g));
// ["getData", "saveData"]

🎭 Analogi sehari-hari: Lookahead/lookbehind = mata-mata cek depan/belakang tanpa pindah posisi. Biasa: "match ABC, lalu konsumsi". Lookahead: "match ABC kalau di depan ada XYZ, tapi gak ambil XYZ ke hasil". Mata-mata intip, gak ngambil. Berguna untuk match by context tanpa include context-nya di output.

💡 Lookahead = composable conditions: ^(?=.*[A-Z])(?=.*\d)(?=.*[!@#]).{8,}$ = password validator. Tiap (?=...) = satu kondisi, semua harus terpenuhi dari posisi awal. Cara terbersih untuk multi-condition validation tanpa parsing manual.

⚠️ Jebakan klasik:

🎯 Pattern lookahead populer:

TL;DR: Alternation | = OR, gunakan group (a|b) untuk batasi scope. Lookahead (?=...) / lookbehind (?<=...) = match by context tanpa konsumsi karakter. Powerful untuk multi-condition validation. Lookbehind di JS perlu cek browser support.