Belajar dengan membaca secara berurutan

Regular Expressions re — Pencarian dan Penggantian Pola

Pelajari modul re Python dari dasar. Mencakup kapan menggunakan re.match / re.search / re.findall, menggabungkan metacharacter \d / \w / \s / * / + / ?, menangkap grup dengan ( ), substitusi dengan re.sub, dan reuse pola dengan re.compile — dengan latihan praktik yang bisa dijalankan.

Artikel ini membahas modul re untuk regular expressions"mengekstrak dan mengganti substring yang cocok dengan pola spesifik". Hal-hal yang sering kamu lakukan di proyek nyata — parsing nomor telepon, email, baris log, dan URL — menjadi one-liner.

Tool untuk mencoba regex secara langsung

Regular expressions punya banyak komponen dan sulit dipikirkan murni di kepala. Untuk mengecek apakah pola kamu cocok seperti yang dimaksud, Regex Extractor berjalan sepenuhnya di browser — ketik pola dan teks lalu lihat kecocokan secara real time. Membukanya di samping artikel ini bikin lebih mudah mengikuti.

match, search, dan findall — Tiga fungsi pencarian dan kapan menggunakan masing-masing

Modul re mengekspos beberapa fungsi pencarian, dan kamu memilih di antara tiga tergantung kebutuhan. Namanya deskriptif — match cocok di awal, search mencari satu kecocokan di mana saja, dan findall menemukan semuanya. Rentang pencarian persis, tipe kembalian, dan perilaku saat tidak cocok dirangkum di tabel berikutnya.

FungsiRentang pencarianMengembalikanSaat tidak cocok
re.matchHanya awal stringMatch objectNone
re.searchKecocokan pertama di mana sajaMatch objectNone
re.findallSemua kecocokanList stringList kosong []

Dari Match object yang dikembalikan re.match dan re.search (objek yang menyimpan posisi match, string yang cocok, dan info grup), kamu membaca string yang cocok dengan memanggil method `.group()`-nya — m.group() atau m.group(0) untuk seluruh match, dan (dengan capture groups yang diperkenalkan nanti) m.group(1) untuk hanya yang ada di dalam tanda kurung. Hanya re.findall mengembalikan list secara langsung, jadi kamu tidak memanggil .group() padanya.

Bagaimana re.match / search / findall Berbeda
re.matchmatch dari awalKalau awal tidak cocok→ Nonere.searchmatch pertama di mana sajaMatch kalau ditemukanNone kalau tidakre.findallsemua kecocokanList string yang cocok([] kalau tidak ada)
match hanya cek apakah pola muncul di awal string. search mengembalikan kecocokan pertama di posisi mana pun. findall mengembalikan setiap kecocokan dalam list.
MetacharacterArtiContoh
\dSatu digit (0-9)\d+ → satu atau lebih digit
\wSatu karakter word (alphanumeric + underscore)\w+ → ID dan keyword
\sSatu karakter whitespace (spasi / tab / newline)Pemisah
.Karakter apa pun kecuali newlineWildcard
*Nol atau lebih dari sebelumnyaa* → kosong juga OK
+Satu atau lebih dari sebelumnyaa+ → minimal satu
?Nol atau satu dari sebelumnyaOpsional
[abc]Salah satu dari a / b / cPilihan
^ / $Awal / akhir stringAnchor
import re

text = "user_id: 12345, age: 30"

# match: dari awal (\w+ adalah deretan karakter word)
m = re.match(r"\w+", text)
print(m.group())            # user_id

# search: deretan digit pertama di mana saja
s = re.search(r"\d+", text)
print(s.group())            # 12345

# findall: setiap deretan digit
nums = re.findall(r"\d+", text)
print(nums)                 # ['12345', '30']

Tulis regex sebagai raw string r"..."

Backslash muncul di mana-mana di dalam regex. String biasa "\d" bisa membuat escape-nya diinterpretasi oleh layer string sebelum re melihatnya, jadi lebih aman menulis raw string `r"\d"` dengan r di depan. Editor juga cenderung menyorot raw string sebagai regex, yang meningkatkan keterbacaan.

Tarik ID dan angka keluar dari satu baris log. Coba re.match / re.search / re.findall terhadap string yang sama dan amati bagaimana hasilnya berbeda.

① Import re.

② Set text = "order_id: 9876, qty: 3, price: 1500".

③ Tarik deretan karakter word dari awal string dan cetak sebagai match: ◯◯.

④ Tarik deretan digit pertama dari string dan cetak sebagai search: ◯◯.

⑤ Tarik setiap deretan digit sebagai list dan cetak sebagai findall: ◯◯.

(Kalau kode berjalan benar, penjelasan akan muncul.)

Python Editor

Jalankan kode untuk melihat output

Capture Groups — Menarik bagian spesifik dari pola

Apa pun yang kamu masukkan ke dalam `( )` di dalam regex menjadi capture group — alih-alih hanya seluruh match, kamu bisa menarik setiap potongan secara terpisah. Pola seperti r"#(\d+) on (\d{4})-(\d{2})-(\d{2})" memungkinkanmu memisahkan nomor pesanan dan tanggal dari baris log dalam sekali jalan.

Panggil `.group(N)` pada Match object untuk membaca grup ke-N (dinomori dari 1). .group(0) (atau .group() tanpa argumen) mengembalikan seluruh match.

Bagaimana Capture Groups Bekerja
#(\d+) on(\d{4})-(\d{2})-(\d{2}).group(0)seluruh match.group(1)nomor pesanan.group(2)tahun.group(3)bulan
Setiap `( )` di regex menjadi grup, dapat diakses dengan indeks 1-based seperti .group(1) / .group(2). .group(0) adalah seluruh match.
import re

text = "Order #1234 placed on 2024-03-15"

# Arti pola:
#   #         → '#' literal
#   (\d+)     → satu atau lebih digit → group(1) nomor pesanan
#   placed on → 'placed on' literal
#   (\d{4})   → 4 digit → group(2) tahun
#   (\d{2})   → 2 digit → group(3) bulan
#   (\d{2})   → 2 digit → group(4) hari
m = re.search(r"#(\d+) placed on (\d{4})-(\d{2})-(\d{2})", text)
if m:
    print("whole:", m.group(0))    # #1234 placed on 2024-03-15
    print("order #:", m.group(1))   # 1234
    print("year:", m.group(2))      # 2024
    print("month:", m.group(3))     # 03
    print("day:", m.group(4))       # 15

Memanggil .group() saat Match adalah None melempar error

Ketika re.search tidak menemukan pola, ia mengembalikan None. Memanggil m.group() pada itu crash dengan AttributeError: 'NoneType' object has no attribute 'group'. Selalu cek dengan `if m:` dulu sebelum .group(), atau lakukan keduanya dalam satu langkah dengan operator walrus: if m := re.search(...): ....

Pisahkan alamat email menjadi nama pengguna dan domain. Gunakan capture groups untuk menarik kedua bagian dalam satu pencarian.

① Import re.

② Set text = "hubungi kami di alice@example.com".

③ Tulis pola email yang menangkap apa yang ada di setiap sisi @ sebagai grup terpisah.

- Kiri: karakter word plus ., +, -, satu atau lebih

- Kanan: jenis karakter sama, berakhir dengan domain seperti .com

④ Saat match ditemukan, cetak `username: ◯◯` dan `domain: ◯◯`.

Python Editor

Jalankan kode untuk melihat output

re.sub — Mengganti kecocokan pola

"Mask PII dari log", "hapus tag HTML dan simpan teks bodi", "normalkan campuran whitespace full-width dan half-width" — semuanya bermuara pada "tulis ulang apa pun yang cocok dengan pola menjadi sesuatu yang lain". replace string hanya menangani substring tetap, tapi re.sub melakukannya berdasarkan pola.

`re.sub(pola, pengganti, asli)` mengembalikan string baru dengan setiap kecocokan diganti oleh pengganti. String asli tidak berubah (string Python immutable, jadi kamu selalu bekerja dengan nilai kembalian).

Cara re.sub Bekerja
String asli"Tel: 03-1234-5678"re.sub(\d, *, ...)String baru"Tel: **-****-****"
Mengembalikan string baru dengan setiap kecocokan diganti oleh string pengganti. Aslinya immutable; terima hasilnya via nilai kembalian.
import re

# Mask digit di nomor telepon (ganti setiap \d dengan satu *)
text = "Tel: 03-1234-5678"
masked = re.sub(r"\d", "*", text)
print(masked)
# Tel: **-****-****

# Hapus tag HTML untuk hanya menyimpan teks bodi
html = "<p>Halo <b>Dunia</b></p>"
plain = re.sub(r"<[^>]+>", "", html)
print(plain)
# Halo Dunia

Mask digit dari nomor telepon mana pun yang muncul di baris log dengan menggantinya menjadi ``.**

① Import re.

② Set text = "Kontak: 03-1234-5678 atau 090-9999-8888".

③ Gunakan re.sub untuk *mengganti setiap digit `\d` dengan satu `**, dan cetak hasilnya sebagai masked: ◯◯`.

④ Cetak text asli lagi sebagai original: ◯◯ untuk memastikan ia tidak berubah (re.sub hanya mengembalikan string baru).

Python Editor

Jalankan kode untuk melihat output

re.compile — Reuse pola

Saat kamu menggunakan regex yang sama berulang-ulang, menulis re.search(r"...", text) berkali-kali membuat engine mem-parse (compile) pola setiap kali, yang merupakan pekerjaan sia-sia. `re.compile(pola)` membangun objek pola yang sudah di-compile sekali, dan kamu memanggil method padanya seperti pattern.search(...) / pattern.findall(...) / pattern.sub(...). Kode lebih mudah dibaca dan berjalan lebih cepat.

Cara re.compile Digunakan
r"\d{2,4}-\d{4}-\d{4}"re.compile(...)phone_re(objek pola)phone_re.search(text)phone_re.findall(text)phone_re.sub("*", text)
`re.compile(pola)` memberimu objek pola yang bisa kamu panggil .search / .findall / .sub sebanyak yang dibutuhkan. Compile saat kamu reuse pola yang sama.
import re

# Reuse pola nomor telepon yang sama
phone_re = re.compile(r"\d{2,4}-\d{4}-\d{4}")

print(phone_re.findall("03-1234-5678 atau 080-1111-2222"))
# ['03-1234-5678', '080-1111-2222']

print(phone_re.search("telepon saya 03-9999-0000").group())
# 03-9999-0000

print(phone_re.sub("<phone>", "Kontak: 03-1234-5678"))
# Kontak: <phone>

Bangun pola nomor telepon sekali dengan `re.compile`, lalu hitung dan substitusi terhadap teks yang sama secara berurutan.

① Import re.

② Set text = "Kontak: 03-1234-5678 atau 090-9999-8888".

③ Compile pola nomor telepon yang 2-4 digit + 4 digit + 4 digit dengan re.compile, dan simpan sebagai phone_re.

④ Gunakan phone_re.findall(text) untuk menghitung berapa banyak nomor telepon yang ada, dan cetak sebagai phone count: ◯.

⑤ Gunakan phone_re.sub untuk mengganti setiap nomor telepon lengkap dengan `<phone>`, dan cetak hasilnya sebagai replaced: ◯◯.

Python Editor

Jalankan kode untuk melihat output
QUIZ

Cek Pemahaman

Jawab setiap pertanyaan satu per satu.

Soal 1Apa yang dikembalikan re.match(r"\d+", "abc 123")?

Soal 2Regex yang benar untuk satu atau lebih digit berturut-turut?

Soal 3Dari re.search(r"(\w+)@(\w+)", "alice@example"), panggilan mana yang mengembalikan hanya domain?

Soal 4Alasan utama untuk menggunakan raw string `r"..."` saat menulis regex di Python?