Pencarian substring literal seperti contains("Kotlin") tidak cukup ketika kita perlu memvalidasi format email, mengekstrak semua tanggal dari dokumen, atau mengganti angka dengan placeholder. Untuk tugas-tugas tersebut, kita membutuhkan regular expression (regex) — bahasa mini untuk mendeskripsikan pola teks. Kotlin menyediakan class Regex yang membungkus java.util.regex.Pattern dengan API yang lebih idiomatik. Pada chapter ini kita akan mempelajari operasi inti (matches, containsMatchIn, find, findAll, replace), penggunaan capture groups, dan named groups yang membuat hasil pencarian menjadi lebih mudah dirujuk dengan nama.
Membuat Instance Regex #
Instance Regex dibuat dengan konstruktor Regex(pattern) atau dengan memanggil pattern.toRegex(). Karena kompilasi pola memerlukan overhead, sebaiknya simpan instance Regex di variabel (atau di properti object) untuk digunakan kembali, terutama bila pola dipakai di dalam loop. Konstruktor juga menerima opsi tambahan seperti RegexOption.IGNORE_CASE.
val pola1 = Regex("[a-zA-Z]+")
val pola2 = "[a-zA-Z]+".toRegex()
val pola3 = Regex("kotlin", RegexOption.IGNORE_CASE)Untuk pola yang mengandung banyak backslash (misalnya \d, \s, \w), gunakan raw string """...""" agar backslash tidak perlu di-escape dua kali: Regex("""\d{4}""") lebih mudah dibaca daripada Regex("\\d{4}").
Lima Operasi Inti #
| Method | Mengembalikan | Kegunaan |
|---|---|---|
matches(input) | Boolean | Seluruh input cocok dengan pola |
containsMatchIn(input) | Boolean | Sebagian input cocok dengan pola |
find(input) | MatchResult? | Kemunculan pertama yang cocok |
findAll(input) | Sequence<MatchResult> | Semua kemunculan yang cocok |
replace(input, replacement) | String | Ganti semua kemunculan |
Method matches bersifat paling ketat: seluruh string harus cocok dengan pola dari awal hingga akhir. Method containsMatchIn lebih longgar: cukup ada satu substring yang cocok. Method find mengembalikan MatchResult? yang berisi teks cocok dan posisi; findAll mengembalikan Sequence yang bisa diiterasi atau dikonversi ke List.
Capture Groups #
Tanda kurung (...) dalam pola membuat capture group — sub-bagian dari kecocokan yang bisa dirujuk secara terpisah. Setiap group diberi nomor mulai dari 1 (group 0 adalah seluruh kecocokan). Method MatchResult.groupValues mengembalikan List<String> dengan indeks sesuai nomor group.
val pola = Regex("""([\w.]+)@([\w.]+)""")
val m = pola.find("[email protected]")
if (m != null) {
println(m.value) // [email protected]
println(m.groupValues[1]) // budi (user)
println(m.groupValues[2]) // example.com (domain)
}Method groupValues selalu berisi seluruh kecocokan di indeks 0, diikuti group bernomor di indeks 1, 2, dst. Untuk group yang tidak berpartisipasi dalam kecocokan tertentu, isi string-nya kosong.
Named Groups #
Ketika pola memiliki banyak group, nomor menjadi sulit dilacak. Kotlin mendukung named group dengan sintaksis (?<name>...). Group bernama ini bisa diakses melalui MatchResult.groups["name"], yang mengembalikan MatchGroup? (nullable bila group tidak berpartisipasi).
val polaTgl = Regex("""(?<tahun>\d{4})-(?<bulan>\d{2})-(?<hari>\d{2})""")
val m = polaTgl.find("Tanggal 2026-01-15 dan 2026-02-20")
if (m != null) {
println(m.groups["tahun"]?.value) // 2026
println(m.groups["bulan"]?.value) // 01
println(m.groups["hari"]?.value) // 15
}Named group sangat berguna untuk pola kompleks seperti ekstraksi log, parsing kode pos, atau tokenisasi. Memberi nama group membuat kode yang membaca hasil pencocokan jauh lebih jelas daripada menggunakan nomor.
replace dengan Regex #
Method replace(input, replacement) mengganti semua kemunculan pola dengan teks pengganti. Dalam string pengganti, kita bisa merujuk group dengan $1, $2 (untuk group bernomor) atau ${name} (untuk named group). Untuk penggantian yang lebih kompleks, gunakan overload replace(input) { match -> ... } yang menerima lambda untuk menghitung teks pengganti per kecocokan.
val teks = "Tahun 2026 sudah tiba"
val hasil = Regex("\\d+").replace(teks) { m ->
"<angka:${m.value}>"
}
println(hasil) // Tahun <angka:2026> sudah tibaLambda menerima MatchResult dan mengembalikan String, sehingga kita bisa melakukan transformasi kontekstual seperti menambah prefix, memformat ulang, atau memetakan nilai ke kamus.
Contoh Lengkap dan Outputnya #
File regex.kt berikut menunjukkan semua operasi di atas:
fun main() {
val polaHuruf = Regex("[a-zA-Z]+")
val teks = "Tahun 2026 versi 2.0"
println("matches '[a-zA-Z]+': ${"Kotlin".matches(polaHuruf)}")
println("matches 'Kotlin2026': ${"Kotlin2026".matches(polaHuruf)}")
println("containsMatchIn: ${polaHuruf.containsMatchIn(teks)}")
val hasil = polaHuruf.find(teks)
println("find pertama: ${hasil?.value}")
val semua = polaHuruf.findAll(teks).map { it.value }.toList()
println("findAll: $semua")
val gantiAngka = Regex("\\d+").replace(teks, "<angka>")
println("replace angka: $gantiAngka")
val polaEmail = Regex("""([\w.]+)@([\w.]+)""")
val kontak = "Email: [email protected] dan [email protected]"
val match = polaEmail.find(kontak)
if (match != null) {
println("Email lengkap: ${match.value}")
println("Grup 1 (user): ${match.groupValues[1]}")
println("Grup 2 (domain): ${match.groupValues[2]}")
}
val polaNama = Regex("""\[(?<nama>[A-Za-z]+)\]""")
val tag = "[Budi] menyapa [Siti]"
polaNama.findAll(tag).forEach { m ->
println("Nama: ${m.groups["nama"]?.value}")
}
val polaTgl = Regex("""(?<tahun>\d{4})-(?<bulan>\d{2})-(?<hari>\d{2})""")
val tgl = "Tanggal 2026-01-15 dan 2026-02-20"
polaTgl.findAll(tgl).forEach { m ->
println("Tahun ${m.groups["tahun"]?.value} bulan ${m.groups["bulan"]?.value} hari ${m.groups["hari"]?.value}")
}
val polaPilihan = Regex("""\b(kotlin|java|python)\b""", RegexOption.IGNORE_CASE)
val kalimat = "Saya suka Kotlin, JAVA, dan Python"
val ditemukan = polaPilihan.findAll(kalimat).map { it.value.lowercase() }.toList()
println("Bahasa ditemukan: $ditemukan")
val dipisah = "satu1dua2tiga".split(Regex("\\d"))
println("split regex: $dipisah")
}Output yang Dihasilkan:
matches '[a-zA-Z]+': true
matches 'Kotlin2026': false
containsMatchIn: true
find pertama: Tahun
findAll: [Tahun, versi]
replace angka: Tahun <angka> versi <angka>.<angka>
Email lengkap: [email protected]
Grup 1 (user): budi
Grup 2 (domain): example.com
Nama: Budi
Nama: Siti
Tahun 2026 bulan 01 hari 15
Tahun 2026 bulan 02 hari 20
Bahasa ditemukan: [kotlin, java, python]
split regex: [satu, dua, tiga]Mari kita telaah bagian penting dari kode di atas. Baris "Kotlin".matches(polaHuruf) memeriksa apakah seluruh string cocok dengan pola — hasilnya true karena "Kotlin" hanya berisi huruf. Sebaliknya, "Kotlin2026".matches(polaHuruf) mengembalikan false karena ada angka. Method findAll mengembalikan Sequence, sehingga kita perlu map { it.value }.toList() untuk mendapatkan List<String> dari teks yang cocok. Pola email ([\w.]+)@([\w.]+) memiliki dua capture group yang diakses melalui groupValues[1] dan groupValues[2]. Named group (?<nama>[A-Za-z]+) diakses melalui m.groups["nama"]?.value. Method split(Regex("\\d")) adalah alternatif split yang menerima pola, bukan literal — berguna ketika delimiter bervariasi (misalnya satu atau lebih whitespace).
Referensi Lanjutan #
- Regex API reference
— API reference class
Regexbesertamatch,find,replace - kotlin.text package
— API reference paket
kotlin.textuntuk utilitas regex
Penutup #
Dengan Regex, kita kini bisa mencari, memvalidasi, dan mengganti teks berdasarkan pola. Banyak operasi regex menghasilkan kumpulan string — baik dari findAll maupun dari split. Operasi kebalikannya, menggabungkan kumpulan string menjadi satu teks, juga sama seringnya. Topik penguraian dan penggabungan teks ini menjadi fokus chapter Splitting dan Joining Text.