Regex Identifier #
Artikel ini adalah referensi lengkap semua identifier — simbol, metacharacter, dan konstruksi sintaksis — yang bisa digunakan dalam regular expression di TypeScript. Berbeda dari artikel Regex sebelumnya yang membahas cara menggunakan regex dan metode-metodenya, artikel ini berfokus pada kamus elemen-elemen penyusun pola regex itu sendiri: apa artinya setiap simbol, bagaimana mereka berinteraksi, dan jebakan apa yang perlu diwaspadai. Jadikan artikel ini sebagai rujukan saat membangun atau membaca pola regex yang kompleks.
Karakter Literal #
Karakter literal adalah karakter yang cocok dengan dirinya sendiri secara tepat. Mayoritas karakter alfanumerik adalah literal:
// Huruf dan angka adalah literal — cocok dengan dirinya sendiri
/abc/.test("abc"); // true — cocok persis
/abc/.test("ABC"); // false — case-sensitive by default
/abc/.test("xabcx"); // true — ditemukan di dalam string
// PERHATIAN: Beberapa karakter punya makna khusus (metacharacter)
// dan harus di-escape dengan \ untuk diperlakukan sebagai literal
// . * + ? ^ $ { } [ ] | ( ) \
/a\.b/.test("a.b"); // true — titik literal
/a\.b/.test("axb"); // false — titik literal hanya cocok dengan "."
Karakter yang Perlu Di-escape #
// Metacharacter yang harus di-escape untuk diperlakukan sebagai literal
const periksaTitikEscaped = /example\.com/; // Titik literal
const periksaBintang = /a\*b/; // Bintang literal
const periksaKurung = /\(ok\)/; // Tanda kurung literal
const periksaSlash = /https:\/\//; // Forward slash dalam literal
// Tabel metacharacter yang perlu di-escape:
// . -> \. titik
// * -> \* bintang
// + -> \+ plus
// ? -> \? tanda tanya
// ^ -> \^ caret (di luar kelas karakter)
// $ -> \$ dollar
// { -> \{ kurung kurawal buka
// } -> \} kurung kurawal tutup
// [ -> \[ kurung siku buka
// ] -> \] kurung siku tutup
// | -> \| pipe
// ( -> \( kurung biasa buka
// ) -> \) kurung biasa tutup
// \ -> \\ backslash
// Helper: escape semua metacharacter dalam string dinamis
function escapeRegex(teks: string): string {
return teks.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
const inputPengguna = "harga: 100.000 (diskon)";
const polaAman = new RegExp(escapeRegex(inputPengguna));
polaAman.test("total harga: 100.000 (diskon) ya"); // true
Metakarakter #
Metakarakter adalah karakter yang memiliki makna khusus dalam pola regex — bukan mencocokkan dirinya sendiri, melainkan mendeskripsikan posisi atau tipe karakter:
. — Titik (Any Character)
#
// Titik cocok dengan SATU karakter apapun kecuali newline (\n)
/a.b/.test("acb"); // true — 'c' cocok dengan titik
/a.b/.test("a b"); // true — spasi cocok dengan titik
/a.b/.test("a\nb"); // false — newline tidak cocok dengan titik (kecuali flag s)
/a.b/.test("ab"); // false — harus ada tepat satu karakter di antara a dan b
// Dengan flag s (dotAll) — titik cocok dengan newline juga
/a.b/s.test("a\nb"); // true — flag s mengaktifkan dotAll mode
// ANTI-PATTERN: Titik sering digunakan terlalu lebar
// /.*/ cocok dengan string apapun termasuk yang tidak diinginkan
// Lebih baik gunakan kelas karakter yang spesifik jika memungkinkan
^ — Caret (Awal String/Baris)
#
// ^ di luar kelas karakter = anchor awal string
/^halo/.test("halo dunia"); // true — dimulai dengan "halo"
/^halo/.test("hai, halo"); // false — "halo" bukan di awal
// Dengan flag m (multiline) — ^ cocok di awal setiap baris
const teksMultibaris = "baris satu\nbaris dua\nbaris tiga";
teksMultibaris.match(/^baris/gm);
// ["baris", "baris", "baris"] — cocok di awal setiap baris
// ^ DI DALAM kelas karakter = negasi (lihat bagian Character Classes)
/[^abc]/.test("d"); // true — 'd' bukan a, b, atau c
$ — Dollar (Akhir String/Baris)
#
// $ = anchor akhir string
/dunia$/.test("halo dunia"); // true — diakhiri dengan "dunia"
/dunia$/.test("dunia baru"); // false — "dunia" bukan di akhir
// Dengan flag m — $ cocok di akhir setiap baris
const teks = "baris satu\nbaris dua";
teks.match(/\w+$/gm);
// ["satu", "dua"] — kata terakhir di setiap baris
// Validasi format lengkap — gunakan ^ dan $ bersamaan
/^\d{5}$/.test("12345"); // true — tepat 5 digit, tidak lebih tidak kurang
/^\d{5}$/.test("123456"); // false — 6 digit
/^\d{5}$/.test("1234"); // false — 4 digit
\b dan \B — Word Boundary
#
// \b = batas kata — posisi antara \w dan \W (atau awal/akhir string)
/\bkata\b/.test("ini kata"); // true — "kata" berdiri sendiri
/\bkata\b/.test("katakata"); // false — tidak ada batas kata
/\bkata\b/.test("kata-kata"); // true — tanda hubung adalah \W
/\bkan\b/.test("akan"); // false — "kan" bagian dari "akan"
// \B = bukan batas kata
/\Bkan\B/.test("seakan"); // true — "kan" di tengah kata
/\Bkan\B/.test("kan"); // false — "kan" berdiri sendiri
// Kasus penggunaan umum: mencari kata utuh
const teks = "TypeScript tidak sama dengan JavaScript";
teks.match(/\bScript\b/g); // null — "Script" bukan kata utuh
teks.match(/\bTypeScript\b/g); // ["TypeScript"] — kata utuh
Kelas Karakter (Character Classes) #
Kelas karakter [...] mencocokkan satu karakter dari kumpulan yang didefinisikan:
// [abc] — cocok dengan a, b, atau c
/[aeiou]/.test("hello"); // true — 'e' dan 'o' adalah vokal
/[aeiou]/.test("rhythm"); // false — tidak ada vokal
// [a-z] — rentang: cocok dengan huruf kecil a sampai z
/[a-z]/.test("Hello"); // true — 'e', 'l', 'l', 'o' dalam rentang
/[A-Z]/.test("hello"); // false — semua huruf kecil
/[0-9]/.test("abc"); // false — tidak ada digit
/[0-9]/.test("abc5"); // true — '5' dalam rentang
// Kombinasi rentang
/[a-zA-Z0-9]/.test("Hello123"); // true — alfanumerik
// [^...] — negasi: cocok dengan karakter yang TIDAK ada dalam kelas
/[^aeiou]/.test("rhythm"); // true — semua karakter bukan vokal
/[^0-9]/.test("abc"); // true — tidak ada digit
/[^0-9]/.test("123"); // false — semua digit
Kelas Karakter Khusus dalam [...]
#
// Di dalam [], beberapa karakter kehilangan makna khususnya
// . tidak perlu di-escape di dalam []
/[.]/.test("."); // true — titik literal di dalam []
/[.]/.test("a"); // false — hanya cocok dengan titik literal
// - harus di posisi pertama, terakhir, atau di-escape untuk menjadi literal
/[-+]/.test("-"); // true — minus di posisi pertama = literal
/[+\-]/.test("-"); // true — minus di-escape = literal
// ^ hanya memiliki makna negasi di posisi pertama
/[a^b]/.test("^"); // true — ^ di tengah = literal
/[^ab]/.test("c"); // true — ^ di awal = negasi
Predefined Character Classes #
Kelas karakter yang sudah didefinisikan sebelumnya sebagai shorthand:
// \d — digit, setara dengan [0-9]
/\d/.test("5"); // true
/\d/.test("a"); // false
// \D — bukan digit, setara dengan [^0-9]
/\D/.test("a"); // true
/\D/.test("5"); // false
// \w — word character, setara dengan [a-zA-Z0-9_]
/\w/.test("a"); // true
/\w/.test("_"); // true
/\w/.test("@"); // false
// PERHATIAN: \w tidak cocok dengan karakter non-ASCII seperti "é", "ñ", "ا"
// \W — bukan word character
/\W/.test("@"); // true
/\W/.test("a"); // false
// \s — whitespace: spasi, tab (\t), newline (\n), carriage return (\r), form feed (\f)
/\s/.test(" "); // true — spasi
/\s/.test("\t"); // true — tab
/\s/.test("\n"); // true — newline
/\s/.test("a"); // false
// \S — bukan whitespace
/\S/.test("a"); // true
/\S/.test(" "); // false
Tabel Predefined Character Classes #
| Identifier | Arti | Setara Dengan |
|---|---|---|
\d | Digit | [0-9] |
\D | Bukan digit | [^0-9] |
\w | Word character | [a-zA-Z0-9_] |
\W | Bukan word character | [^a-zA-Z0-9_] |
\s | Whitespace | [ \t\n\r\f\v] |
\S | Bukan whitespace | [^ \t\n\r\f\v] |
. | Karakter apapun (kecuali \n) | [^\n] |
\n | Newline | — |
\t | Tab | — |
\r | Carriage return | — |
Unicode Property Escapes (Flag u)
#
Dengan flag u, TypeScript/JavaScript mendukung pencocokan berdasarkan properti Unicode — sangat berguna untuk teks multibahasa:
// \p{properti} — cocok karakter dengan properti Unicode tertentu
// Memerlukan flag u
/\p{L}/u.test("A"); // true — huruf (Letter)
/\p{L}/u.test("1"); // false — bukan huruf
/\p{L}/u.test("ا"); // true — huruf Arab
/\p{L}/u.test("你"); // true — karakter Cina
/\p{N}/u.test("5"); // true — angka (Number)
/\p{P}/u.test("."); // true — tanda baca (Punctuation)
/\p{Script=Arabic}/u.test("ا"); // true — karakter Arab
/\p{Script=Latin}/u.test("A"); // true — karakter Latin
/\p{Script=Han}/u.test("你"); // true — karakter Han (Cina/Jepang/Korea)
/\p{Emoji}/u.test("😊"); // true — emoji
/\p{Emoji}/u.test("A"); // false
// \P{} = negasi dari \p{}
/\P{L}/u.test("1"); // true — bukan huruf
Quantifier — Mengontrol Pengulangan #
Quantifier menentukan berapa kali elemen sebelumnya harus muncul:
Quantifier Dasar #
// * — 0 atau lebih (greedy)
/ab*c/.test("ac"); // true — 0 'b'
/ab*c/.test("abc"); // true — 1 'b'
/ab*c/.test("abbbc"); // true — 3 'b'
// + — 1 atau lebih (greedy)
/ab+c/.test("ac"); // false — harus ada minimal 1 'b'
/ab+c/.test("abc"); // true — 1 'b'
/ab+c/.test("abbbc"); // true — 3 'b'
// ? — 0 atau 1 (opsional, greedy)
/colou?r/.test("color"); // true — tanpa 'u'
/colou?r/.test("colour"); // true — dengan 'u'
// {n} — tepat n kali
/\d{4}/.test("2025"); // true
/\d{4}/.test("202"); // false — kurang dari 4
// {n,} — minimal n kali
/\d{3,}/.test("123"); // true
/\d{3,}/.test("12"); // false
// {n,m} — antara n sampai m kali (inklusif)
/\d{2,4}/.test("12"); // true — 2 digit
/\d{2,4}/.test("1234"); // true — 4 digit
/\d{2,4}/.test("12345"); // true — cocok 4 digit di awal
/\d{2,4}/.test("1"); // false — 1 digit
Greedy vs Lazy vs Possessive #
const html = "<b>tebal</b> dan <i>miring</i>";
// Greedy — ambil sebanyak mungkin (default)
html.match(/<.+>/)?.[0]; // "<b>tebal</b> dan <i>miring</i>"
// Lazy — ambil sesedikit mungkin (tambahkan ? setelah quantifier)
html.match(/<.+?>/)?.[0]; // "<b>"
// Tabel: Greedy → Lazy
// * → *? (0 atau lebih, lazy)
// + → +? (1 atau lebih, lazy)
// ? → ?? (0 atau 1, lazy)
// {n,m} → {n,m}? (rentang, lazy)
// Contoh nyata: ekstrak semua tag HTML
const semuaTag = html.match(/<.+?>/g);
// ["<b>", "</b>", "<i>", "</i>"]
// vs greedy yang hanya mengambil dari < pertama ke > terakhir
const greedy = html.match(/<.+>/g);
// ["<b>tebal</b> dan <i>miring</i>"]
Grouping dan Capturing #
(...) — Capturing Group
#
// Capturing group menangkap bagian yang cocok untuk diakses kembali
const tanggal = /(\d{4})-(\d{2})-(\d{2})/.exec("2025-05-07");
if (tanggal) {
console.log(tanggal[0]); // "2025-05-07" — kecocokan penuh
console.log(tanggal[1]); // "2025" — grup 1
console.log(tanggal[2]); // "05" — grup 2
console.log(tanggal[3]); // "07" — grup 3
}
// Backreference dalam pola — \1 merujuk ke isi grup 1
// Berguna untuk mencari pengulangan kata
/(\b\w+\b) \1/.test("halo halo"); // true — kata diulang
/(\b\w+\b) \1/.test("halo dunia"); // false — kata berbeda
// Backreference dalam replace — $1, $2, dst
"2025-05-07".replace(/(\d{4})-(\d{2})-(\d{2})/, "$3/$2/$1");
// "07/05/2025"
(?:...) — Non-capturing Group
#
// Non-capturing group — kelompokkan tanpa tangkap indeks
// Berguna untuk grouping alternation atau quantifier tanpa overhead
// Tanpa non-capturing: "ab" ditangkap sebagai grup
/(ab)+/.exec("ababab")?.[1]; // "ab" — hanya tangkapan TERAKHIR
// Dengan non-capturing: tidak ada tangkapan, lebih efisien
/(?:ab)+/.exec("ababab")?.[1]; // undefined — tidak ada grup
// Kasus umum: kelompokkan alternation
/(?:https?|ftp):\/\//.test("https://example.com"); // true
/(?:https?|ftp):\/\//.test("ftp://files.com"); // true
(?<nama>...) — Named Capturing Group
#
// Named group — akses lewat .groups.nama bukan indeks
const formatISO = /(?<tahun>\d{4})-(?<bulan>\d{2})-(?<hari>\d{2})/;
const hasilISO = formatISO.exec("tanggal: 2025-05-07");
if (hasilISO?.groups) {
const { tahun, bulan, hari } = hasilISO.groups;
// tahun: string, bulan: string, hari: string
console.log(`${hari} ${['','Jan','Feb','Mar','Apr','Mei','Jun','Jul','Agu','Sep','Okt','Nov','Des'][parseInt(bulan)]} ${tahun}`);
// "07 Mei 2025"
}
// Named backreference — \k<nama>
/(?<kata>\b\w+\b) \k<kata>/.test("halo halo"); // true — kata diulang
Alternation #
// | — OR: cocok dengan salah satu dari pola yang dipisahkan
/kucing|anjing/.test("saya punya kucing"); // true
/kucing|anjing/.test("saya punya anjing"); // true
/kucing|anjing/.test("saya punya ikan"); // false
// Alternation dalam group — membatasi scope |
/^(senin|selasa|rabu|kamis|jumat)$/.test("senin"); // true
/^(senin|selasa|rabu|kamis|jumat)$/.test("sabtu"); // false
/^(senin|selasa|rabu|kamis|jumat)$/.test("senin "); // false — ada spasi
// Alternation mencoba dari kiri ke kanan — urutan penting!
// "ab" vs "a" — "ab" harus di kiri agar bisa cocok dulu
/ab|a/.exec("ab")?.[0]; // "ab" — "ab" dicoba dulu
/a|ab/.exec("ab")?.[0]; // "a" — "a" cocok duluan!
Assertions #
Assertions cocok dengan posisi dalam string, bukan karakter:
// ^ dan $ sudah dibahas di Metakarakter di atas
// \b — word boundary
/\bTypeScript\b/.test("TypeScript itu keren"); // true
/\bScript\b/.test("TypeScript"); // false — bagian dari kata
// \B — non-word boundary (kebalikan \b)
/\Btype\B/.test("prototype"); // true — "type" di tengah kata
/\Btype\B/.test("type"); // false — "type" berdiri sendiri
// Zero-width: assertions tidak mengonsumsi karakter
// Ini berarti cocok pada POSISI, bukan karakter
const hasil = "abc".match(/(?=b)/);
// Cocok di posisi sebelum 'b', tapi tidak mengonsumsi 'b'
Lookahead dan Lookbehind (Lengkap) #
Lookaround adalah zero-width assertion yang memeriksa konteks tanpa termasuk dalam hasil:
// =============================================
// LOOKAHEAD
// =============================================
// (?=pola) — Positive Lookahead: cocok jika diikuti pola
"100px 200em 300px".match(/\d+(?=px)/g);
// ["100", "300"] — angka yang diikuti "px"
// (?!pola) — Negative Lookahead: cocok jika TIDAK diikuti pola
"100px 200em 300px".match(/\d+(?!px)(?!\d)/g);
// ["200"] — angka yang tidak diikuti "px"
// =============================================
// LOOKBEHIND
// =============================================
// (?<=pola) — Positive Lookbehind: cocok jika didahului pola
"$100 €200 £300".match(/(?<=\$)\d+/g);
// ["100"] — angka yang didahului "$"
// (?<!pola) — Negative Lookbehind: cocok jika TIDAK didahului pola
"$100 €200 £300".match(/(?<!\$)\d+/g);
// ["200", "300"] — angka yang tidak didahului "$"
// (abaikan fakta bahwa ini bisa lebih komplex di implementasi nyata)
// =============================================
// KOMBINASI LOOKAROUND
// =============================================
// Ekstrak nilai di antara tag tertentu
const xml = "<nama>Budi Santoso</nama>";
xml.match(/(?<=<nama>).+?(?=<\/nama>)/)?.[0];
// "Budi Santoso" — tanpa tag
// Validasi password dengan lookahead:
// min 8 karakter, minimal 1 huruf besar, 1 huruf kecil, 1 angka
const regexPassword = /^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,}$/;
regexPassword.test("Password1"); // true
regexPassword.test("password1"); // false — tidak ada huruf besar
regexPassword.test("PASSWORD1"); // false — tidak ada huruf kecil
regexPassword.test("Pass1"); // false — kurang dari 8 karakter
Tabel Referensi Cepat Semua Identifier #
KARAKTER LITERAL
abc — Huruf/angka literal
\. — Titik literal (escape metacharacter)
METAKARAKTER
. — Karakter apapun kecuali \n (atau semua dengan flag s)
^ — Awal string (atau awal baris dengan flag m)
$ — Akhir string (atau akhir baris dengan flag m)
\b — Word boundary
\B — Non-word boundary
KELAS KARAKTER
[abc] — Salah satu: a, b, atau c
[^abc] — Bukan a, b, atau c
[a-z] — Rentang huruf kecil
[A-Z] — Rentang huruf besar
[0-9] — Rentang digit
[a-zA-Z0-9] — Gabungan rentang
PREDEFINED CLASSES
\d — Digit [0-9]
\D — Bukan digit [^0-9]
\w — Word char [a-zA-Z0-9_]
\W — Bukan word char
\s — Whitespace
\S — Bukan whitespace
\p{L} — Letter Unicode (flag u)
\p{N} — Number Unicode (flag u)
\p{Emoji} — Emoji (flag u)
QUANTIFIER (GREEDY)
* — 0 atau lebih
+ — 1 atau lebih
? — 0 atau 1
{n} — Tepat n kali
{n,} — Minimal n kali
{n,m} — Antara n dan m kali
QUANTIFIER (LAZY — tambah ?)
*? — 0 atau lebih (lazy)
+? — 1 atau lebih (lazy)
?? — 0 atau 1 (lazy)
{n,m}? — Antara n dan m (lazy)
GROUPING
(pola) — Capturing group
(?:pola) — Non-capturing group
(?<nama>) — Named capturing group
(a|b) — Alternation dalam group
BACKREFERENCE
\1 \2 ... — Backreference by index
\k<nama> — Backreference by name
$1 $2 ... — Dalam replace (by index)
$<nama> — Dalam replace (by name)
LOOKAROUND
(?=pola) — Positive lookahead
(?!pola) — Negative lookahead
(?<=pola) — Positive lookbehind
(?<!pola) — Negative lookbehind
ESCAPE SEQUENCES
\n — Newline
\t — Tab
\r — Carriage return
\0 — Null character
\uXXXX — Unicode character (hex)
\u{XXXXX} — Unicode codepoint (flag u)
Ringkasan #
- Escape metacharacter dengan
\saat ingin mencocokkan mereka sebagai literal — karakter. * + ? ^ $ { } [ ] | ( ) \semuanya punya makna khusus.- Gunakan fungsi
escapeRegex()saat membangun pola dari input pengguna atau data dinamis untuk mencegah karakter metacharacter tidak sengaja mengubah perilaku pola.[...]cocok dengan satu karakter — bukan urutan karakter;[abc]cocok dengan ‘a’ atau ‘b’ atau ‘c’, bukan dengan string “abc”.^di dalam[^...]adalah negasi, bukan anchor —[^abc]artinya “karakter apapun selain a, b, c”.\wtidak mendukung karakter non-ASCII — huruf Arab, aksara Jawa, atau karakter berdiakritik tidak cocok dengan\w; gunakan\p{L}dengan flaguuntuk pencocokan multibahasa yang benar.- Greedy adalah default — quantifier
+,*,?,{n,m}mengambil sebanyak mungkin; tambahkan?setelahnya (+?,*?) untuk lazy yang mengambil sesedikit mungkin.- Named capturing group
(?<nama>pola)jauh lebih mudah dibaca daripada indeks angka — gunakan untuk pola dengan lebih dari dua grup.- Lookaround adalah zero-width — mereka memeriksa konteks di sekitar posisi tanpa mengonsumsi karakter, sehingga tidak muncul dalam hasil kecocokan.
- Urutan alternation penting —
|mencoba dari kiri ke kanan dan berhenti saat pertama cocok; letakkan pola yang lebih panjang/spesifik di kiri agar tidak tergeser oleh pola yang lebih pendek.