Regular Expression

Belajar dan mengenal regex menggunakan lumpia framework

Masih pada materi dasar, materi yang sebagian besar orang terlihat membosankan. Karena hasilnya tidak langsung tampak indah. Namun materi dasar adalah pondasi. Tanpa memahami materi dasar, alhasil mentok sana sini.

Regex Lumpia
Belajar Regex pada Lumpia Framework

So, bagi yang belum paham bagaimana menggunakan regex.. silakan dibaca dan dipahami materi ini yak.

ReGex

ReGex merupakan kepanjangan dari Regular Expression.

Perlu diperhatikan saja, regex tiap bahasa pemrograman itu agak berbeda-beda. Meski terlihat sama, tapi ada aja bedanya.

Karena lumpia framework berjalan pada bahasa pemrograman javascript, jadi kata kuncinya adalah regex javascript.

Definisi

 

definisi regex


 

Definisinya regex adalah..
Hmm cari aja deh di google hehe.

Karena bukan perkuliahan yang perlu dibahas secara spesifik dan tuntas, kita cukup ambil poin-poin pentingnya saja di sini yak.

Kalau versi saya sih simple saja, yakni buat nangkap atau ngambil karakter (text) dengan pola tertentu.

Kenapa REGEX?

definisi regex

Mungkin awalnya rumit, tapi setelah mengalami sendiri ketika ada kasus yang komplek harus dikelola.

Maka regex ini menjadi kunci dalam pembuatan bot (proses menangkap, memfilter, mengubah, dan atau menyajikan data) spesifik.

Bahkan hampir setiap penggunaan pada lumpia framework adalah berdasarkan regex.

Coba mari kita perhatikan, bila menggunakan gaya umum untuk mendapatkan seluruh angka dari teks:

umur 21 tahun, berangkat jam 13:00 WIB

bakal ribet memecah-mecahnya.

Dengan mengenal regex, akan terasa mudah mendapatkannya.

… karena regex adalah kunci.

Syntax

Yuk, kita mulai..

Rumusnya selalu diawali dan diakhiri dengan garis miring: /pola/
kemudian dilanjutkan simbol flag jika ada.

/pola/flag

Pemahamanan

Maksud pola adalah pola yang akan kita tangkap pada sebuah teks, misalnya kita akan deteksi kalimat yang ada kata halo nya. Maka penulisannya adalah: /halo/

Sementara flag adalah kondisi tertentu yang diinginkan, misalnya tidak membedakan huruf besar dan huruf kecil pada pola, maka bisa pakai flag i

Sehingga: /halo/i maka ketika user mengetik Halo, halo, haLO, atau HALO dimana saja posisinya, boleh di depan tengah atau belakang, semuanya tetap terdeteksi.

Penerapan

Bagaimana penerapan nya pada bot Telegram yang menggunakan lumpia?

Gunakanlah method hear atau hears untuk mendeteksinya.

Syntax Lumpia:

bot.hears(regex, callback);

Sehingga:

bot.hears(/halo/i, ctx => {
    ctx.reply('halo juga');
})

Simple kan :-D

OKEH, lanjoet..

Tanda Khusus

Tanda khusus yang memiliki arti spesial pada regex. Ga semua harus dihapali, tapi ini yang sering dipakai ya:

  • ^ caping atas artinya diawal kata / kalimat
  • $ dolar, artinya diakhir kalimat
  • . titik berarti sembarang karakter, kecuali ganti baris
  • * artinya 0 karakter atau lebih (banyak)
  • + artinya 1 karakter atau lebih (banyak)
  • ? artinya 0 atau 1. Misal: https? artinya boleh http atau https
  • \b penanda satu kata penuh
  • {m,n} artinya minimal m dan maksimal n, misal A{1,3} artinya huruf A minimal 1 dan maksimal 3
  • [] grup karakter ATAU sebanyak 1 aja, misal [abc] boleh a, b atau c.
  • [^abc] grup yang BUKAN berisi itu di dalamnya
  • | karakter ATAU
  • \w huruf alphabetnumeric. Senilai pola: [a-zA-Z0-9_]
  • \n ganti baris
  • \s spasi
  • \0 karakter null
  • \d artinya digit atau angka, senilai pola [0-9]
  • (...) tanda kurung, berarti hasilnya digrup
  • (?:...) digrup tapi tidak dimasukkan dalam tangkapan
  • (?<nama>...) digrup dan diberi nama

Masih banyak tanda khusus, namun itu yang bakal sering kita pakai ya.

Flag

Flag yang sering dipergunakan:

  • i ignore case untuk tidak membedakan huruf besar dan kecil
  • g global mencari semua pola yang cocok
  • m multiline cari di semua baris
  • u support karakter unicode

Masih ada beberapa flag, namun diawal kita perlu mengenal 3 itu saja dulu. Untuk pendahuluan yang mudah dihapal dan sering dipakai.

Escape

Karena karakter / sudah dipakai sebagai penanda regex. Maka jika ingin menuliskan karakter itu harus di escape penulisannya, dengan karakter backslash \.

Karakter-karakter spesial yang harus di escape adalah semua karakter yang telah disebutkan diatas.

Misalnya untuk menangkap user mengetik apa kabar?, maka penulisan polanya adalah:

/apa kabar\?/

tanpa di escape, tanda tanya (?) akan untuk penangkapan ada huruf r atau tidak.

Contoh lainnya, misalnya:

  • titik: menjadi \.
  • buka kurung: \(
  • plus: \+
  • dst

Use Case

Biar lebih aktual dan lebih dapat feel pemahamannya, langsung saja kita menuju beberapa contoh, kasus, dan implementasinya.

Ping

Ini contoh simple sekaligus untuk menunjukkan escape karakter khusus.

Misal:

User: /ping
Bot : Pong!

Karena kita inginkan pola yang ditangkap adalah ada garis miringnya, maka itu harus di escape.

//ping/i
/\/ping/i

Penjelasan:

  • Garis miring / untuk /ping HARUS di escape dengan backslash : \/
  • Tidak membedakan huruf besar dan kecil dengan flag i
  • Jika tulisan ping hanya boleh diawal teks, maka tandai dengan caping ^, sehingga menjadi: /^\/ping/i
  • terakhir, jika hanya kata ping saja, tidak boleh ada teks lain, maka akhiri dengan tanda $, sehingga finalnya menjadi: /^\/ping$/i

Code pada lumpia framework:

bot.hears(/^\/ping$/i, ctx => {
    ctx.reply('pong!');
})

Sehingga, user mengetik /ping saja (boleh huruf besar atau kecil) yang akan direspon.

user: /ping
bot: pong!

user: /PING
bot: pong!
user: ping
user: piiingg
user: makan emping
user: pingin mie rebus
user: !ping
user: kepingin beli lumpia

Silakan di test, dengan cara re-deploy atau dengan handleUpdate pada lumpia.

Umur

Kasus lain, ada yang ingin menangkap dengan angka saja. Misalnya kebutuhannya disuruh memasukkan umur.

User: umur 21 tahun
Bot : 21

Akan kita tangkap angka 21 nya sesudah user mengetikkan dengan diawali kata umur

Pola nya adalah:

/umur (\d+)/i

Artinya yang akan kita tangkap dengan grup kurung () adalah \d adalah angka saja, dengan terserah panjangnya asalkan minimal 1 karakter angka (makna tanda +).

Pemakaiannya:

bot.hears(/umur (.+)/i, ctx => {
    ctx.reply(ctx.match[1]);
}

Penjelasannya:

  • ctx.match adalah hasil tangkapan group regexnya
  • text yang diinput user, boleh diletakkan di depan, tengah atau akhir.
  • contoh text di awal, user mengetikkan: umur 21 atau umur 21 th
  • contoh text di tengah, user mengetikkan: aku berumur 21 tahun

Echo

Sekarang kita buat fungsi trigger dimana bot akan memantulkan isi text.

Misal:

User: !echo Halo mas
Bot : Halo mas

Maka, pola-nya adalah sebagai berikut:

/^!echo (.+)/i

Maksudnya:

  • ^ kata !echo harus diawal kalimat. Tidak ditengah atau diakhir.
  • () adalah grup pertama untuk hasil yang ditangkap.
  • . sembarang karakter kecuali ganti baris
  • + perulangan sembarang karakter, apa aja minimal 1 sampai tidak terbatas

Sehingga, code pemakaian pada lumpia framework:

bot.hears(/^!echo (.+)/i, ctx => {
    ctx.reply(ctx.match[1]);
}

Penjelasan detailnya mirip dengan /ping

::: warning Silakan dipahami secara perlahan-lahan… :::

Tempat Tanggal Lahir

Misalnya disuruh memasukkan tempat tanggal lahir.

User: !echo Kediri, 23-06-2001
Bot : Kamu lahir di Kediri, tanggal 23-06-2001

Pola deteksi tanggal sederhananya adalah:

/^!echo (.*),\s*(\d\d-\d\d-\d{4})$/i

Artinya :

  • Detek tempat lahir dengan karakter apa saja (.*) sampai ketemu koma.
  • \s* sesudah koma, ada spasi atau tidak, tetep kedetek
  • \d artinya angka, jika \d\d artinya angka dijejer 2x (atau 2 digit)
  • \d{4} artinya angka yang dijejer 4

Code pemakaiannya:

var pola = /^!echo (.*),\s*(\d\d-\d\d-\d{4})$/i;

bot.hears(pola, ctx => {
    ctx.reply("Kamu lahir di "+ctx.match[1]+", tanggal "+ctx.match[2]);
}

Dengan pola penulisan tanggal sederhana ini, secara umum bisa ditangkap dan mudah dipahami.

Namun, ada yang ingin lebih memfilternya atau membuat lebih detail.

Contoh pola kompleksnya:

var pola = /^!echo (.*),\s*((0?[1-9]|[12][0-9]|3[01])-(0?[1-9]|1[012])-\d{4})/i;

Yang ini ga usah diartikan haha.. Cuma buat pelengkap saja agar paham banyak cara menangkap sekaligus mevalidasinya.

Validasinya adalah tanggal tidak boleh lebih dari 31, dan bulan tidak boleh lebih dari 12.

Multiline

Pada beberapa kasus, ada yang ingin menangkap berbaris-baris pesan.

Contoh ini dapat kita temui pada kasus bot hastags.

User:

!echo Puisi Rahasia

Aku akan menulis
sebuah puisi rahasia
tapi ini rahasia ya
rahasia sekali

Maaf, ini rahasia.
Selesai.

Contohnya seperti itu. Bagaimana menangkapnya?

Ada banyak cara atau metode. Namun, cara yang saya sukai adalah dengan menangkap pesan statisnya (!echo), kemudian membuangnya. Dengan demikian, pesan dinamisnya akan kita dapatkan akhirnya.

Pesan statisnya dikit, jadi itu saja yang ditangkap. Maka pesan statis dibuatkan group.

Pola:

/^(!echo )/i

Dan kodenya seperti ini kira-kira:

bot.on(/^(!echo )/i, ctx =>{
    // buang pola yang di dapatkan dengan menggantinya dengan karakter kosong atau tidak ada
    let pesan = ctx.message.text.replace(ctx.match[1],'');
    ctx.reply(pesan);
})

Dengan cara demikian, kita akan mendapatkan isi pesan secara penuh bebas diisi karakter apa saja.

Sapaan Halo

Agar bot terkesan ramah, kadang perlu kita buat bot sapaan.

Kadang ga cukup kata halo, ada yang yang nulisnya macam-macam: halo, hallo, hai, dan seterusnya.

  • Level 1:

Data semua kata yang memungkinkan dipakai:

pola /(halo|hallo)/i

Artinya, pola yang akan ditangkap kata halo, atau hallo yang letaknya dimana saja maka bot akan meresponnya.

Kodenya seperti ini kira-kira:

var pola = /(halo|hallo|helo|hello|hai|hay)/i;

bot.hears(pola, ctx => {
    ctx.reply('Halo juga!');
}

Mari kita tingkatkan dan kembangkan secara bertahap.

Lain-lain

Ada banyak contoh kasus lainnya. Namun, silakan banyak-banyak mencoba sesuai dengan kasus masing-masing.

Karena regex itu ilmu praktek dan latihan, jadi teman-teman harus mencobanya sendiri.

Sekadar buat tambahan referensi, tak perlu diambil hati.. copas aja kalau butuh hehe.

  • Hashtag: /^#[^ !@#$%^&*(),.?":{}|<>]*$/i
  • ASCII: /[ -~]/gm
  • URL: /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()!@:%_\+.~#?&\/\/=]*)/i
  • Email Simple: /[^@ \t\r\n]+@[^ @\t\r\n]+\.[^@ \t\r\n]+/i
  • Email Komplek: /(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/i
  • Nomor Telp: /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/gmi
  • Emoticon: /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/gm
  • ipv4: /(\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}/gm
  • ipv6: /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/gm
  • port: /^((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{0,5})|([0-9]{1,4}))$/
  • latitude, longitude: /^((\-?|\+?)?\d+(\.\d+)?),\s*((\-?|\+?)?\d+(\.\d+)?)$/i
  • version: /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/i

Video

Code

Berikut ini source code pada video.

Referensi

Tulisan ini disadur dari blog bangHasan.

Akhir Kata

Jika ingin live dan biasanya tanggapan juga lebih cepat, sangat disarankan bergabung pada group Telegram @botIndonesia.

🙏🏼 Semoga bermanfaat …