Cheat sheet ini merangkum semua yang sudah kamu pelajari di track regex, satu baris per pola. Anggap saja kartu resep yang ditempel di pintu kulkas Bu Ratna: bukan buat dihafal, tapi dilirik waktu sedang masak, dan tiap resep di kartu itu sudah pernah dicoba. Di sini juga begitu: kolom kanan tiap tabel adalah hasil asli menjalankan contohnya di Node 22, kebanyakan pada chat, chat PO Dapur Ratna yang menemani kita dari pelajaran pertama. Cara pakainya: cari yang kamu butuhkan di kolom "Artinya", salin contohnya, lalu ganti teksnya.
🧪 Tebakan cepat: pola
/\d*.\d+/dipakai untuk mencari angka desimal seperti3.14, tapi titiknya lupa diberi backslash. Apakah pola itu juga menerima"314", yang gak punya titik sama sekali? Tebak dulu, jawabannya ada di bagian "Karakter dan class".
Karakter dan class
| Pola | Artinya | Dites |
|---|---|---|
nastar |
huruf apa adanya, besar-kecil dibedakan | chat.match(/nastar/g) → ['nastar'] |
. |
satu karakter apa saja, kecuali baris baru | chat.match(/k.k/g) → ['kak', 'kak'] |
\. |
titik asli (karakter khusus di-escape) | "3.14 0.5 314".match(/\d*\.\d+/g) → ['3.14', '0.5'] |
\d, \D |
angka 0 sampai 9; bukan angka | "PO-0412".match(/\D+/)[0] → 'PO-' |
\w, \W |
huruf, angka, dan underscore ([A-Za-z0-9_]); selain itu |
"[email protected]".match(/\W/g) → ['.', '@', '.'] |
\s, \S |
spasi, tab, baris baru; selain itu | "hp +62 857-1122-3344".match(/\S+/g) → ['hp', '+62', '857-1122-3344'] |
[*_~] |
satu karakter dari daftar | chat.match(/[*_~]/g).length → 6 |
[^\d.] |
satu karakter selain daftar | "Rp85.000".match(/[^\d.]+/)[0] → 'Rp' |
[a-z] |
satu karakter dalam rentang | "NASTAR 3 toples".match(/[a-z]+/g) → ['toples'] |
\p{L} + flag u |
huruf apa pun, termasuk é |
"café".match(/\p{L}+/gu) → ['café'], sedangkan /\w+/g → ['caf'] |
Tanpa backslash, titik artinya "karakter apa saja". Jadi /\d*.\d+/.test("314") memberi true: . memakan angka 1. Itu jawaban tebakannya. Untuk desimal, tulis /\d*\.\d+/.
Quantifier
| Pola | Artinya | Dites |
|---|---|---|
* |
0 kali atau lebih | "tples toples tooples".match(/to*ples/g) → ['tples', 'toples', 'tooples'] |
+ |
1 kali atau lebih | chat.match(/\d+rb/g) → ['90rb', '255rb'] |
? |
0 atau 1 kali (opsional) | "+62 857 0812".match(/\+?\d+/g) → ['+62', '857', '0812'] |
{4} |
tepat 4 kali | chat.match(/PO-\d{4}/g) → ['PO-0412', 'PO-0413'] |
{10,} |
minimal 10 kali | chat.match(/\d{10,}/g) → ['1234567890', '081298765432'] |
{1,3} |
1 sampai 3 kali | chat.match(/Rp\d{1,3}\.\d{3}/g) → ['Rp85.000', 'Rp165.000', 'Rp170.000'] |
+?, *? |
lazy: sesedikit mungkin | chat.match(/\*.+?\*/g) → ['*Nastar*', '*Kastengel*', '*Putri Salju*'] |
Tanpa ?, \*.+\* itu greedy dan mengambil satu potongan panjang dari *Nastar* sampai *Putri Salju*.
Anchor dan batas kata
| Pola | Artinya | Dites |
|---|---|---|
^ |
awal teks; awal tiap baris dengan flag m |
chat.match(/^\[/gm).length → 6, tanpa m → 1 |
$ |
akhir teks; akhir tiap baris dengan flag m |
chat.match(/PO-\d{4}$/gm) → ['PO-0412', 'PO-0413'], tanpa m → ['PO-0413'] |
\b |
batas kata | "kak, kakak".match(/\bkak\b/g) → ['kak'], tanpa \b → ['kak', 'kak'] |
Group, pilihan, dan lookaround
| Pola | Artinya | Dites |
|---|---|---|
(...) |
group yang menangkap | chat.match(/tgl (\d{2})\/(\d{2})/).slice(1) → ['25', '03'] |
(?:...) |
group tanpa menangkap | chat.match(/\d+(?:rb|k)\b/g) → ['90rb', '75k', '255rb'] |
(?<hari>...) |
named group | chat.match(/tgl (?<hari>\d{2})/).groups.hari → '25' |
\1 |
teks yang sama dengan group 1 | chat.match(/([*_~])[^*_~]+\1/g) → ['*Nastar*', '*Kastengel*', '*Putri Salju*'] |
a|b |
atau | chat.match(/nastar|kastengel/gi) → ['Nastar', 'Kastengel', 'nastar', 'kastengel', 'NASTAR'] |
(?=...) |
sesudahnya harus ada | chat.match(/\d+(?=rb)/g) → ['90', '255'] |
(?!...) |
sesudahnya gak boleh ada | "90rb 75k".match(/\d+(?!\d|rb)/g) → ['75'] |
(?<=...) |
sebelumnya harus ada | chat.match(/(?<=Rp)[\d.]+/g) → ['85.000', '165.000', '170.000'] |
(?<!...) |
sebelumnya gak boleh ada | "PO-0412 WA 0812".match(/(?<!-)\b\d{4}\b/g) → ['0812'] |
Lookbehind (?<=...) dan (?<!...) jalan di Safari sejak versi 16.4.
Flag
| Flag | Artinya | Dites |
|---|---|---|
g |
semua kecocokan, bukan cuma yang pertama | chat.match(/PO-(\d{4})/) → ['PO-0412', '0412'], dengan g → ['PO-0412', 'PO-0413'] |
i |
abaikan besar-kecil huruf | chat.match(/nastar/gi) → ['Nastar', 'nastar', 'NASTAR'] |
m |
^ dan $ berlaku per baris |
lihat baris ^ dan $ di atas |
s |
. ikut mencocokkan baris baru |
/Kode.+Dina/.test(chat) → false, dengan s → true |
u |
mode Unicode: \p{...} jalan, emoji dihitung satu karakter |
/^.$/.test("😀") → false, dengan u → true |
y |
sticky: cuma mencoba tepat di lastIndex |
const y = /PO-\d{4}/y; y.lastIndex = 121; y.test(chat) → true |
Tanpa flag u, \p{L} bukan property escape: "p{L}".match(/\p{L}/)[0] memberi 'p{L}'.
Method JavaScript
| Method | Hasilnya | Dites |
|---|---|---|
re.test(teks) |
true atau false |
/PO-\d{4}/.test(chat) → true |
teks.match(re) |
tanpa g: kecocokan pertama dan group-nya; dengan g: semua teks yang cocok; gak ada: null |
lihat baris flag g |
teks.matchAll(re) |
semua kecocokan lengkap dengan group (wajib g) |
[...chat.matchAll(/PO-(\d{4})/g)].map((m) => m[1]) → ['0412', '0413'] |
re.exec(teks) |
satu kecocokan; dengan g lanjut dari lastIndex |
/PO-(\d{4})/.exec(chat).index → 121 |
teks.replace(re, x) |
teks baru; replaceAll wajib g |
"0812-3456-7890".replace(/-/g, "") → '081234567890' |
teks.search(re) |
posisi kecocokan pertama, atau -1 |
chat.search(/PO-/) → 121 |
teks.split(re) |
array potongan | "+62 857-1122-3344".split(/[- ]/) → ['+62', '857', '1122', '3344'] |
Pola siap pakai
| Untuk | Pola | Dites |
|---|---|---|
| Harga singkat | /\d+(?:rb|k)\b/g |
di chat → ['90rb', '75k', '255rb'] |
| Harga Rp | /Rp\d{1,3}(?:\.\d{3})+/g |
di chat → ['Rp85.000', 'Rp165.000', 'Rp170.000'] |
| Nomor HP Indonesia | /(?:\+62 ?|0)8\d{2}[- ]?\d{4}[- ]?\d{3,4}/g |
di chat → ['0812-3456-7890', '+62 857-1122-3344', '081298765432'] |
| Rapikan HP jadi +62 | .replace(/[^\d+]/g, "").replace(/^0/, "+62") |
"0812-3456-7890" → '+6281234567890' |
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ |
"[email protected]" → true, "[email protected]" → false |
|
| Nama tanpa ReDoS | /^\w+(?:\s\w+)*$/ |
"Putri Salju" → true |
Tanggal YYYY-MM-DD |
/^(\d{4})-(\d{2})-(\d{2})$/ |
"2026-03-25" → group ['2026', '03', '25'] |
| Titik ribuan | .replace(/\B(?=(\d{3})+(?!\d))/g, ".") |
"1250000" → '1.250.000' |
| Escape isian pengguna | .replace(/[.*+?^${}()|[\]\\]/g, "\\amp;") |
"Rp85.000 (nastar)" → 'Rp85\.000 \(nastar\)' |
Pola email di atas memeriksa bentuk: [a-zA-Z0-9._%+-]+ bagian sebelum @, lalu domain, titik, dan akhiran minimal 2 huruf.
⚠️ Jebakan yang sering ketemu
- Titik tanpa backslash.
.artinya karakter apa saja; titik asli ditulis\.. - Lupa
^dan$saat validasi. Tanpa keduanya, sepotong teks yang benar sudah cukup untuktrue. - Regex ber-
gdipakai ulang untuktest().lastIndexterbawa, jadi hasilnya bisa berganti-ganti. - Quantifier di dalam quantifier, seperti
(\w+)+atau(\w+\s?)+, bisa macet (ReDoS) pada isian panjang yang gagal di ujung. - Pola disalin ke bahasa lain tanpa dicek. Python memakai
(?P<nama>...)dan\1di teks pengganti, PHP butuh pembatas dan gak punya flagg, Go gak punya lookaround dan backreference.
TL;DR: Cheat sheet = rujukan cepat yang tiap barisnya sudah dites. Inti yang paling sering dipakai: \d (angka), \w (huruf, angka, dan underscore), \s (spasi), . (apa saja, jadi titik asli ditulis \., misalnya /\d*\.\d+/ untuk 3.14), class [...], quantifier * + ? {n,m} (tambah ? untuk lazy), anchor ^ $ \b, group ( ), (?: ), (?<nama> ), pilihan |, dan lookaround (?= ), (?! ), (?<= ), (?<! ). Flag: g semua, i abaikan besar-kecil, m per baris, s titik ikut baris baru, u mode Unicode untuk \p{...} dan emoji, y sticky. Pola email /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ memeriksa bentuk alamat email. Tes selalu dengan isian yang benar dan yang salah.