2.35. Dasar-dasar pola

Ekspresi reguler adalah bahasa kecil untuk mendeskripsikan string berdasarkan bentuknya daripada isinya yang tepat. Gunakan ketika sebuah string cocok jika dan hanya jika mengikuti sebuah pola yang bisa Anda deskripsikan tetapi tidak dapat Anda enumerasi -- "urutan angka diikuti oleh satuan", "baris yang dimulai dengan ERROR dan diakhiri dengan angka", "salah satu dari ekstensi file ini, dalam urutan apa pun, dengan awalan v opsional".

Gunakan re hanya ketika metode string biasa tidak mencukupi.

Setiap metode tersebut lebih cepat, lebih mudah dibaca, dan lebih sulit salah daripada regex yang setara. Gunakan regex ketika bentuk string yang penting dan substring tepatnya tidak.

2.35.1. Empat hal yang akan Anda gunakan

Modul MicroPython re menyediakan empat hal:

  • re.compile() -- ubah string pola menjadi objek pola yang sudah dikompilasi yang dapat Anda gunakan kembali.

  • re.match() -- coba pola di awal sebuah string. Pola dijangkarkan pada posisi 0.

  • re.search() -- coba pola di mana saja dalam sebuah string. Mengembalikan pencocokan pertama.

  • re.sub() -- temukan setiap pencocokan dan gantikan.

Perbedaan penting vs CPython: tidak ada re.findall, tidak ada re.finditer, tidak ada re.split di level modul (pola yang dikompilasi memiliki metode split sebagai gantinya), tidak ada re.fullmatch, tidak ada konstanta flag seperti re.IGNORECASE. Jika Anda ingin menggunakan salah satunya di CPython, buat yang setara dari re.search() dalam sebuah loop.

2.35.2. Pola pertama

Pola r'\d+' mencocokkan satu atau lebih angka:

>>> import re
>>> m = re.search(r'\d+', 'sensor reading 42 ok')
>>> m.group(0)
'42'

Beberapa hal yang perlu diperhatikan:

  • Pola ditulis sebagai raw string (r'...') sehingga backslash dalam \d sampai ke re alih-alih diproses sebagai escape string Python. Selalu gunakan raw string untuk pola regex.

  • re.search() mengembalikan objek pencocokan jika berhasil dan None jika gagal. Selalu periksa sebelum memanggil match.group().

  • m.group(0) adalah teks lengkap yang cocok dengan pola. Grup 1, 2, ... muncul kemudian, setelah pola berisi tanda kurung tangkapan.

Pola yang sama dengan re.match() mengembalikan None karena string tidak dimulai dengan angka:

>>> re.match(r'\d+', 'sensor reading 42 ok') is None
True
>>> re.match(r'\d+', '42 readings')
<match num=1>

2.35.3. Bagian-bagian dari sebuah pola

Pola yang paling berguna dibangun dari sekumpulan kecil bagian. Yang berfungsi di MicroPython:

Karakter literal -- karakter mana pun yang bukan khusus mencocokkan dirinya sendiri. hello mencocokkan hello.

Karakter khusus -- . ^ $ * + ? { } [ ] \ | ( ) semuanya memiliki arti di bawah. Untuk mencocokkan salah satunya secara literal, escapekan dengan backslash: \. mencocokkan titik literal.

Kelas karakter -- singkatan untuk kumpulan karakter umum:

  • \d -- digit mana pun 0-9

  • \D -- bukan digit mana pun

  • \s -- karakter spasi putih mana pun (spasi, tab, baris baru)

  • \S -- bukan spasi putih mana pun

  • \w -- karakter "kata" mana pun: huruf, angka, garis bawah

  • \W -- karakter bukan kata mana pun

  • . -- karakter mana pun kecuali baris baru

Kuantifier -- berapa kali bagian sebelumnya harus cocok:

  • * -- nol atau lebih (serakah)

  • + -- satu atau lebih (serakah)

  • ? -- nol atau satu

  • {n} -- tepat n

  • {m,n} -- antara m dan n (inklusif)

Menggabungkan: \d{3}-\d{4} mencocokkan tiga angka, tanda hubung, empat angka. \s+ mencocokkan satu atau lebih karakter spasi putih. hello.*world mencocokkan hello, apa pun (termasuk kosong), lalu world.

Catatan

Serakah berarti kuantifier mengonsumsi sebanyak mungkin input sementara masih memungkinkan sisa pola cocok. Terhadap hello x world y world, .* dalam hello.*world mencocokkan urutan terpanjang yang masih menyisakan world di akhir -- ia menangkap x world y, bukan yang lebih pendek x. Hal yang sama berlaku untuk + dan bentuk rentang {m,n}: mesin mengambil pencocokan terpanjang yang bisa, lalu mundur hanya jika sisa pola gagal.

2.35.4. Substitusi

re.sub() menemukan setiap pencocokan dan menggantinya dengan sebuah string. Pengganti dapat merujuk grup yang ditangkap melalui \1, \2, ... (dibahas bersama sisa sintaksis grup nanti). Tanpa grup, re.sub adalah temukan-dan-ganti langsung pada regex:

>>> re.sub(r'\s+', ' ', 'too    many   spaces')
'too many spaces'

>>> re.sub(r'\d+', 'N', 'log 12, log 345, log 6')
'log N, log N, log N'

Argumen ketiga adalah string yang dioperasikan; hasilnya adalah string baru dengan setiap pencocokan diganti.

2.35.5. Pemisahan -- hanya pada pola yang dikompilasi

Tidak ada re.split di level modul. Untuk memisahkan berdasarkan regex, kompilasi pola terlebih dahulu dan panggil metode split-nya:

>>> sep = re.compile(r'\s*,\s*')
>>> sep.split('a , b,c ,  d')
['a', 'b', 'c', 'd']

Argumen kedua opsional membatasi jumlah pemisahan:

>>> sep.split('a, b, c, d', 2)
['a', 'b', 'c, d']

2.35.6. Mengompilasi untuk digunakan kembali

Jika pola yang sama dijalankan berkali-kali -- di dalam loop atau dalam fungsi yang sering dipanggil -- kompilasi sekali dan gunakan kembali objek yang dikompilasi:

digit_run = re.compile(r'\d+')

def first_number(line):
    m = digit_run.search(line)
    return int(m.group(0)) if m else None

Memanggil pattern.match() dan pattern.search() pada objek yang dikompilasi sama dengan fungsi level modul tetapi melewatkan biaya kompilasi ulang pada setiap panggilan.

2.35.7. Pola yang tidak mencocokkan apa pun

Tiga pola khususnya sering membuat pengembang terkejut:

  • .* mencocokkan string kosong. re.search(r'.*', s).group(0) mengembalikan '' untuk input apa pun.

  • Pola dengan karakter khusus yang tidak di-escape adalah kesalahan sintaksis. re.compile(r'cost: $5') memunculkan ValueError karena $ berarti "akhir string". Gunakan r'cost: \$5'.

  • Titik . tidak mencocokkan baris baru. Untuk mencocokkan melewati baris baru, tulis pola untuk menanganinya secara eksplisit dengan [\s\S] atau berikan satu baris sekaligus.

Dengan bagian-bagian ini sebuah pola dapat mencocokkan hampir semua irisan teks berformat tetap. Menarik data terstruktur dari pencocokan membutuhkan grup tangkapan.