- Crate Rust
regexsetelah bertahun-tahun penulisan ulang membuka sebagian besar mesin internalnya sebagai API crateregex-automataversi terpisah, dan transisi ini selesai diregex 1.9 - Penulisan ulang ini berangkat dari sulitnya mengombinasikan strategi pencarian, sulitnya pengujian tiap mesin internal, kebutuhan akan API multi-pattern yang lebih rinci daripada
RegexSet, serta perlunya berbagi DFA hasil kompilasi penuh regex-automatamenyusun pemrosesan regex dengan alurAst → Hir → ekstraksi literal/Prefilter → Thompson NFA → PikeVM·BoundedBacktracker·one-pass DFA·DFA·lazy DFA → meta engine- Kinerja diperoleh dengan sebisa mungkin mengutamakan pencarian literal dan mesin keluarga DFA, lalu dilengkapi dengan
PikeVM, bounded backtracker, atau one-pass DFA saat ada capture group atau kasus pengecualian - API publik dan abstraksi yang dapat digunakan ulang mempermudah pengujian dan eksperimen, tetapi jumlah kode, ukuran biner, dan waktu kompilasi meningkat; DFA hasil kompilasi penuh dijadikan opt-in, dan
regex-liteditambahkan sebagai alternatif ringan
Penulisan ulang regex dan publikasi regex-automata
regexcrate di Rust ditulis ulang selama bertahun-tahun untuk memperbaiki komposisi internal, memudahkan penambahan optimisasi, dan tetap menjaga ketepatan- Dalam proses ini,
regex-automatadibuat dan mengekspos sebagian besar implementasi internal crateregexsebagai API terpisah regex-automatadiperkenalkan sebagai kasus pertama yang membuka bagian internal library regex sejauh ini sebagai library berversi terpisahregex 1.9dirilis pada 5 Juli 2023 dan menuntaskan penulisan ulang ini- Ditujukan untuk programmer Rust dan orang-orang yang tertarik pada implementasi mesin regex berbasis finite automata, dengan asumsi sudah memiliki pengalaman regex
Masalah-masalah sebelum penulisan ulang
- Crate
regexlama mengikuti tradisi RE2 dan secara internal memakai beberapa strategi pencarian, tetapi karena strategi-strategi itu ditambahkan secara organik, kombinasinya menjadi sulitPikeVMdirancang sebagai strategi pertama, sehingga kurang memiliki penanganan mulai/berhenti pencarian partial slice yang dibutuhkan saat dikombinasikan dengan lazy DFA- Sulit menalar strategi mana yang dipakai untuk regex tertentu
- Beberapa ekspresi
matchmengimplementasikan logika yang sama berulang kali sehingga mudah tidak sinkron - Bahkan untuk regex yang cukup memakai Aho-Corasick saja, Thompson NFA yang tidak akan dipakai bisa tetap dibuat secara tidak perlu
- Pengujian mesin internal juga rumit
- API publik terlihat seperti satu mesin regex, tetapi di dalamnya ada banyak strategi yang harus berperilaku sama untuk input yang sama
- Sebelum
regex 1.9, strategi internal bukan API publik sehingga sulit menguji tiap mesin secara terpisah - Pengujian lama memiliki struktur yang nyaris berupa hack, bergantung pada eksposur API internal, implementasi
Fromyang tidak didokumentasikan, macro, dan target pengujian per mesin
- Ada juga banyak permintaan API niche yang sulit dimasukkan ke permukaan API lama
RegexSethanya memberi tahu pola mana yang cocok di suatu bagian haystack, tetapi tidak menyediakan offset match maupun offset capture group- Diperlukan kemampuan menjalankan pencarian anchored tanpa menambahkan
^ke pola - Ada kebutuhan untuk mengirim mutable scratch space secara langsung tanpa sinkronisasi internal selama pencarian
- Ada pula permintaan menjalankan regex pada haystack tidak kontinu seperti stream atau rope
- Dengan membuka internal sebagai crate berversi terpisah, API
regexserbaguna tidak perlu dibuat lebih rumit, sementara API untuk pengguna ahli bisa dieksperimenkan dengan siklus breaking change yang lebih cepat
Batas abstraksi yang dibentuk DFA hasil kompilasi penuh
- Motivasi awal
regex-automataadalah menyediakan runtime minimal yang bisa membuat DFA hasil kompilasi penuh, menserialisasinya, lalu melakukan pencarian lewat deserialisasi zero-copy regex-automataawalnya dipakai untuk membuat DFA bagi implementasi algoritme Unicode dibstr- Saat membangun DFA, ternyata dibutuhkan struktur data NFA dan compiler yang mirip dengan crate
regex, dan ketika kode ini makin kompleks, kebutuhan untuk berbagi pun meningkat - Awalnya sempat dipertimbangkan crate terpisah seperti
regex-nfa, tetapi lebih banyak kode—termasuk proses determinisasi—ternyata bisa dibagi antararegexdanregex-automata - Batas abstraksinya lebih dekat ke mesin regex daripada sekadar “NFA”, dan pada akhirnya
regex-automatadidefinisikan ulang sebagai kumpulan beberapa mesin - Rencana jangka panjangnya adalah menempatkan semua mesin regex di
regex-automatadan menjadikan crateregexsebagai wrapper tipis di atasnya
Melihat struktur internal dengan regex-cli
regex-cliadalah program yang dikelola di repositori crateregex, dan menyediakan akses baris perintah ke berbagai API dariregex-syntax,regex-automata, danregex- Instalasinya dapat dilakukan dengan perintah berikut
cargo install regex-cli
regex-cli debugdapat menampilkan AST, HIR, literal, Thompson NFA, one-pass DFA, dense DFA, sparse DFA, dan lain-lain- Regex
.dengan Unicode aktif membuat Thompson NFA yang jauh lebih kompleks untuk menangani UTF-8 scalar value, sedangkan(?-u:.)dengan Unicode nonaktif membuat NFA yang lebih sederhana regex-cli findbisa menjalankan pencarian sementara, dan dengan meta engine juga dapat melakukan pencarian multi-pattern serta menampilkan capture group
Alur data pemrosesan regex
- String pola yang diberikan ke
Regex::newpertama-tama diparse menjadiAst Astkemudian diubah menjadiHirHirmemiliki detail lebih sedikit daripadaAst, dan Unicode case folding serta referensi Unicode character class diperluas selama proses konversi
- Dari
Hir, ada dua hal yang dihasilkan- Urutan literal yang dipakai untuk optimisasi pencarian
- Thompson
NFA
- NFA menjadi dasar untuk membangun berbagai mesin
PikeVM: menangani semua regex yang bisa diparse dan melaporkan offset capture groupBoundedBacktracker: melaporkan offset capture group dengan bounded backtracking- one-pass DFA: pada regex yang terbatas, dapat melaporkan offset capture group dengan cepat
- dense DFA: sangat cepat tetapi hanya melaporkan awal/akhir full match, dan pembentukannya dalam kasus terburuk memerlukan waktu dan ruang
O(2^m) - lazy DFA: membangun DFA dari NFA selama pencarian, biasanya secepat full DFA sambil menghindari biaya konstruksi eksponensial dari full DFA
- Mesin-mesin ini bersama
Prefilterdigabung menjadi satu meta regex engine, dan crateregexadalah wrapper tipis di atas meta engine tersebut
Optimisasi literal
- Ekstraksi literal adalah optimisasi inti di dalam
regex- Misalnya, semua kecocokan dari
(foo|bar|quux)(\s+\w+)dimulai dengan salah satu darifoo,bar, atauquux
- Misalnya, semua kecocokan dari
- Alasan literal penting adalah karena algoritme pencarian satu string atau sejumlah kecil string sangat cepat
- Dengan instruksi vektor, beberapa byte dari haystack dapat diproses sekaligus
- Algoritme pencocokan regex umum sulit dipercepat secara konsisten dengan cara yang sama
- Pencarian substring yang dioptimalkan dengan baik sering kali setidaknya satu orde magnitudo lebih cepat daripada mesin regex umum
- Ekstraksi literal bersifat heuristik
- False positive rate dari kandidat kecocokan harus dikurangi
- Dampak prefilter terhadap latensi total juga harus rendah
- Kedua kondisi ini sama-sama bergantung pada haystack, tetapi menganalisis haystack sebelum pencarian dapat memperburuk waktu pencarian total
- Urutan literal bukan himpunan, melainkan sekuens berurutan
- crate
regexmengikuti semantik leftmost-first ala Perl, sehingga|tidak memenuhi sifat komutatif sam|samwisemungkin hanya mengekstraksam, tetapisamwise|sammempertimbangkan keduanya
- crate
- Untuk pencarian satu string, digunakan modul
memmemdari cratememchr- Algoritme utamanya adalah Two-Way dengan waktu terburuk
O(n)dan ruang konstan - Rabin-Karp digunakan untuk needle dan haystack yang pendek
- Pada
x86_64, digunakan varian SIMD generik
- Algoritme utamanya adalah Two-Way dengan waktu terburuk
- Untuk pencarian banyak string, Teddy yang di-port dari Hyperscan digunakan sebagai algoritme utama, dan dalam beberapa kasus Aho-Corasick juga dipakai
Thompson NFA dan optimisasi
- Struktur data utama di dalam crate
regexadalah Thompson NFA - Thompson’s construction membangun NFA dari representasi terstruktur regex dalam waktu
O(m), denganmsebanding dengan ukuran regex setelah ekspansi counted repetition - NFA dapat digunakan langsung sebagai mesin regex, dan juga dapat dikonversi ke tipe lain seperti DFA sebagai dasar bagi mesin lain
- Optimisasi utama pada kompiler NFA baru berfokus pada pengurangan epsilon transition
- Thompson NFA bagus dari sisi waktu konstruksi, tetapi banyak menggunakan epsilon transition
- Perhitungan epsilon closure dapat menimbulkan biaya berulang saat pencarian atau selama konstruksi DFA
- Optimisasi state
sparsemerepresentasikan banyak transisi rentang dalam satu state untuk mengurangi beberapa instructionSplityang sebelumnya diperlukan- Ini menghilangkan epsilon transition yang tidak perlu pada regex seperti
[A-Za-z0-9] - Dalam representasi saat ini, ada kemungkinan dampak pada cache dan peningkatan heap memory karena indirection
- Ini menghilangkan epsilon transition yang tidak perlu pada regex seperti
- Optimisasi minimal UTF-8 automata sangat mengurangi ukuran NFA pada Unicode class yang besar
- Pada NFA berorientasi byte lama,
\wdapat menghasilkan 3.564 state - Kompiler baru menggunakan Daciuk’s algorithm untuk membuat struktur dengan jauh lebih sedikit state dan tanpa epsilon transition
- Penyusutan reverse NFA saat ini dinonaktifkan secara default karena biaya compile time
- Pada NFA berorientasi byte lama,
- Optimisasi literal trie mengompilasi alternation literal seperti
zap|z|zapper,abc|xyzke trie untuk mengurangi epsilon transition dengan memanfaatkan struktur bersama- Untuk mempertahankan semantik leftmost-first, transition chunk dibagi di setiap titik tempat match dapat muncul
- Pekerjaan NFA ke depan mencakup kajian terhadap Glushkov NFA dan penyimpanan dalam satu contiguous allocation
- Glushkov NFA tidak memiliki epsilon transition, tetapi kompleksitas compile time-nya lebih buruk
- Contiguous allocation dapat memberikan cache friendliness dan kemungkinan serialisasi/deserialisasi zero-copy, tetapi ada potensi kompleksitas kode dan penggunaan
unsafe
Mesin regex individual
- Mesin-mesin di
regex-automataberbagi API yang serupaInput: mengatur haystack, rentang pencarian, apakah anchored, dan apakah early stop diaktifkanMatch: berisi span byte yang cocok danPatternIDMatchError: menunjukkan error ketika hasil pencarian tidak dapat ditentukan
-
PikeVM
- Mendukung seluruh fitur yang dapat di-parse oleh
regex-syntax, dan bekerja pada haystack dengan panjang berapa pun - Melacak posisi grup tangkapan dan menghitung state aktif secara lock-step untuk menjamin waktu terburuk
O(m * n) - Kelemahan utamanya adalah performa, karena harus melacak banyak state dan posisi grup tangkapan
- Memiliki sifat unik di antara mesin
regex-automata, yaitu tidak mengembalikan error selama pencarian
- Mendukung seluruh fitur yang dapat di-parse oleh
-
BoundedBacktracker
- Menggunakan backtracking di atas Thompson NFA, tetapi memakai state tambahan agar pekerjaan yang sudah dilakukan tidak dilacak ulang
- Menjamin waktu terburuk
O(m * n), tetapi menggunakan ruangO(m * n) - Dalam eksperimen kasar, biasanya sekitar 2 kali lebih cepat daripada
PikeVM - Dapat gagal jika panjang haystack dan ukuran regex melebihi visited capacity yang telah ditetapkan
-
one-pass DFA
- Melaporkan offset grup tangkapan dengan sangat cepat pada one-pass NFA yang terbatas
- Dianggap sebagai cara tercepat untuk melaporkan grup tangkapan
- Hanya mendukung anchored search, dan banyak regex bukan one-pass
- Dalam mode Unicode, regex yang bukan one-pass karena overlap transisi level byte dapat menjadi one-pass jika Unicode dimatikan
-
fully compiled DFA
- Terdiri dari dua DFA, forward DFA dan reverse DFA, untuk menemukan akhir dan awal kecocokan penuh
- Konstruksinya memiliki waktu dan ruang terburuk
O(2^m), dan dense DFA menggunakan banyak memori - Mesin full DFA dinonaktifkan secara default di crate
regexdan harus diaktifkan secara opt-in melalui featureperf-dfa-full - Berjalan tanpa
Cacheyang mutable, dan dapat diserialisasi sebagai raw bytes sehingga runtime pencarian bisa dipakai bahkan di lingkungan yang hanya memilikicore
-
hybrid NFA/DFA, lazy DFA
- Mirip dengan full DFA, tetapi membangun transition table selama pencarian
- Jika transition yang sudah dihitung ada di cache, transition itu digunakan kembali; jika tidak, hanya transition tersebut yang dihitung melalui NFA powerset construction
- Waktu pencarian terburuk adalah
O(m * n), dan ruang dibatasi oleh cache capacity yang ditentukan saat konstruksi - Dalam kasus umum, sebagian besar state dan transition tersimpan di cache sehingga perilakunya rata-rata seperti
O(n), dan pada praktiknya menunjukkan performa pencarian yang mirip dengan full DFA untuk banyak regex - Jika cache berulang kali penuh dan menjadi tidak efisien, mesin ini mengembalikan error, dan pada meta engine biasanya pencarian dicoba ulang dengan mesin lain
Peran meta regex engine
meta regex enginebertujuan menyatukan beberapa engine menjadi satu dan menyediakan API yang infallible kepada pemanggil- Pemanggil tidak perlu membuat dan meneruskan
Cachesecara langsung untuk setiap pencarian- meta engine mengelola pool cache internal yang thread-safe
- jika ingin menghindari biaya sinkronisasi, tersedia juga API level lebih rendah yang secara eksplisit menerima
Cache
regex::Regex,regex::RegexSet,regex::bytes::Regex,regex::bytes::RegexSetsemuanya merupakan wrapper tipis dari meta engine- Strategi internal meta engine secara garis besar adalah sebagai berikut
- jika bisa ditangani hanya dengan pencarian substring tunggal atau jamak tanpa regex engine, maka pembuatan NFA juga dihindari
- jika memungkinkan, mengekstrak urutan literal prefix untuk digunakan sebagai
Prefilter - jika prefix tidak cocok, mencoba optimisasi reverse anchored, reverse suffix, dan reverse inner
- selain itu, fallback ke strategi inti yang mencakup
PikeVM, bounded backtracker, one-pass DFA, lazy DFA, dan full DFA
- Seluruh strategi dapat diringkas menjadi dua kalimat
- sebisa mungkin mencari literal
- sebisa mungkin menghindari penggunaan
PikeVM
- Optimisasi reverse suffix dan reverse inner dapat menjadi kasus terburuk
O(m * n^2)terhadap ukuran haystack jika salah diterapkan- meta engine mendeteksi situasi ketika reverse scan hendak melewati akhir match suffix sebelumnya, lalu fallback ke strategi inti untuk mempertahankan jaminan kompleksitas waktu
Perbedaan dengan RE2
regexcrate dan RE2 memiliki banyak kemiripan- RE2 juga memiliki NFA yang setara dengan PikeVM, bitstate backtracker, one-pass NFA, lazy DFA, serta struktur yang menggabungkan beberapa engine
- dari engine di atas, yang tidak ada di RE2 adalah fully compiled DFA
- Perbedaan utamanya adalah sebagai berikut
- RE2 mendukung semantik leftmost-longest ala POSIX sebagai opsi selain leftmost-first
- dukungan Unicode di RE2 lebih terbatas, dan tidak ada opsi untuk menggunakan
\w,\s,\d,\bdengan definisi Unicode - dukungan RE2 untuk operasi himpunan character class selain union terbatas
- PikeVM milik RE2 mungkin lebih efisien dalam penggunaan memori
- optimisasi literal di RE2 terbatas, dan
regexcrate melakukan lebih banyak optimisasi literal - lazy DFA RE2 membuat beberapa thread berbagi transition cache yang sama sehingga memerlukan sinkronisasi, sedangkan
regexcrate mewajibkan cache terpisah per thread sehingga memakai lebih banyak memori regexcrate merilisregex-syntaxdanregex-automatasebagai library terpisah dengan versi sendiri, tetapi RE2 tidak mendukung iniregex-automatamendukung multi-pattern regex sebagai first-class di semua engine, dan juga dapat melaporkan match serta offset capture group dari setiap pola yang cocok
Strategi pengujian dan benchmark
- Strategi pengujian baru menjadikan engine internal sebagai API first-class yang independen dan menguji setiap engine secara langsung
- Semua pengujian regex ditentukan dalam file TOML
- crate
regex-testmembaca pengujian TOML dan mengubahnya menjadi representasi terstruktur - Untuk setiap konfigurasi engine, ada satu Rust unit test yang menjalankan semua pengujian TOML yang berlaku untuk engine tersebut
- Karena framework Rust unit test tidak dapat diperluas, ditambahkan infrastruktur environment variable khusus untuk memfilter pengujian tertentu
- Hanya di
regex-automatasaja ada lebih dari 450 documentation test - Dalam persiapan
regex 1.9, banyak target fuzz testing juga ditambahkan, dan dengan bantuan Addison Crump ditemukan beberapa bug - Benchmark dipublikasikan melalui regex barometer bernama
rebarrebarmembenchmark tidak hanyaregexcrate tetapi juga berbagai regex engine lain- pada 242 benchmark,
regex 1.9rata-rata 1,5 kali lebih cepat daripadaregex 1.7.3berdasarkan waktu pencarian - waktu untuk membangun regex sedikit mengalami regresi
1.8adalah transition release yang mencakup sebagian pekerjaan migrasi, sehingga1.7digunakan sebagai titik pembanding
Biaya dan alternatif ringan
- Penulisan ulang ini menghabiskan sebagian besar waktu luang penulis selama beberapa tahun terakhir, dan proyek seperti ripgrep sempat tidak bisa dirilis untuk sementara waktu
- Abstraksi publik yang dapat digunakan ulang cenderung menghasilkan lebih banyak kode dibanding abstraksi yang hanya untuk internal
- akibatnya, ukuran biner dan waktu kompilasi meningkat
- Karena API engine internal dipublikasikan sebagai versi terpisah, untuk memecahkan API diperlukan breaking change release yang sesuai dari
regex-automata - Untuk meredakan biaya, dua langkah diterapkan
- engine fully compiled DFA dinonaktifkan secara default dan dijadikan feature opt-in
regex-litedirilis sebagai crate baru
regex-litemenargetkan hampir menjadi drop-in replacement untukregexcrate, tetapi berfokus pada optimisasi ukuran biner dan waktu kompilasi- mengorbankan fitur Unicode dan performa
- tetap mempertahankan jaminan kompleksitas waktu
O(m * n) - tidak memiliki dependensi, menyertakan parser regex sendiri, dan tidak berbagi kode dengan
regexcrate
regex-litemasih merupakan langkah mitigasi yang eksperimental, tetapi menunjukkan bahwa meskipun optimisasi dan fitur Unicode dimatikan lewat feature diregexcrate, hasilnya tetap sulit mendekati ukuran biner dan waktu kompilasi milikregex-lite
1 komentar
Komentar Hacker News
Baru sekilas membaca saja, crate regex Rust sudah terasa sangat mengesankan
BurntSushi punya banyak karya hebat, tetapi crate regex Rust itu benar-benar legendaris, dan fakta bahwa ekosistem Rust sudah lama punya pustaka regex yang cepat dan mudah dipakai adalah berkah besar bagi komunitas
Seri tulisan regex dari Russ Cox juga luar biasa, jadi ketika regex mulai terasa seperti persimpangan sempurna antara teori dan praktik, saya menjadikannya rujukan saat membuat mesin regex selama musim panas
Perubahan pengujian yang lebih mendalam di tulisan ini juga menarik, dan karena ini crate yang krusial bagi ekosistem, penjelasan tentang topik sedalam ini sangat diapresiasi
Regex kadang sulit dibaca dan juga sering disalahgunakan untuk hal seperti validasi email, tetapi tetap menjadi salah satu alat paling padat guna di hampir semua bahasa
Untuk buku praktis, yang saya kenal baik hanya Mastering Regular Expressions karya Jeffrey Friedl, sedangkan sisi teorinya dibahas di buku-buku compiler, dan Dragon Book juga lumayan dari sudut pandang implementasi. Saya penasaran dengan rekomendasi buku regex lainnya
Pendekatannya adalah membuat nondeterministic finite automaton untuk regex, lalu menelusuri graf berarah hasilnya dan menganggapnya cocok jika bisa mencapai simpul yang sesuai dengan keadaan akhir
Bagi orang yang memakai regex, latihan ini membantu memahami bahwa sebenarnya tidak terlalu banyak “sihir” di baliknya, dan jika membayangkan bola-bola memantul di atas NFA, bug catastrophic backtracking yang akhirnya ditemui di production juga jadi terasa punya makna fisik
Terkait tulisan aslinya, komentar terakhir BurntSushi di https://github.com/rust-lang/regex/issues/822 menambahkan konteks yang berguna pada paragraf API niche https://blog.burntsushi.net/regex-internals/#problem-request.... Mencari banyak regex sekaligus dalam teks itu sangat rumit tetapi juga sangat berguna, jadi saya menantikan apa yang akan dibangun komunitas dengan pola ini
Misalnya format dengan jumlah field tetap seperti
header:field1,field2,field3\"data\"hash, atau format sepertisuite~split/test1,test2@opt1:opt2^hw1^hw2#flags1#flags2di mana sebagian besar elemennya opsional; alat dasar sepertisplittidak memadai dan regex jauh lebih cocokDi sinilah alasan regex cepat menjadi sulit dibaca. Dalam satu regex, delimiter antar-field, validitas tiap field, dan field mana yang opsional semuanya bercampur
Padahal itu sebenarnya tiga perhatian terpisah, tetapi kebanyakan API regex tidak memungkinkan pemisahan bertahap seperti itu dan hanya menerima satu string gabungan saja
Karena keterbatasan bahasa dan status perlindungan hak cipta, saya harus membangun sendiri fitur RegEx, dan regex kadang benar-benar terasa seperti ilmu voodoo
Saya tidak tahu seberapa sering mesin lain dipakai, tetapi jika banyak bahasa pemrograman menggunakan PikeVM, saya bisa mengerti mengapa Google membuat OS khusus internal untuk server dan mengerahkan mesin yang lebih cepat dalam situasi tertentu demi menghemat beberapa clock cycle saja
Saya sangat paham bahwa menambahkan hanya beberapa karakter pada string pencarian bisa sangat memperlambat pattern matching. Pepatah “jaga recehan, nanti uang besarnya menjaga dirinya sendiri” juga sangat cocok untuk RegEx dan clock cycle, dan jika melihat kembali percakapan era 90-an tentang memproses jutaan record per detik, ini mungkin telah membuat beberapa coder menjadi sangat kaya
Terutama karena cara menangani tanda kutip atau mengakhiri ekspresi sangat berbeda tergantung dialek dan konteksnya, saya sudah menyerah untuk menghafalnya dan memilih mencari contoh setiap kali diperlukan
Di ActiveState, saya pernah diberi tugas bersama rekan yang baru lulus kuliah untuk membuat debugger regex bagi editor Komodo
Kami mempekerjakan pakar Perl legendaris Mark Jason Dominus untuk menanamkan hook ke mesin regex Perl, lalu mengekspos hook itu ke UI agar pengguna bisa melihat eksekusi regex langkah demi langkah
Sekarang alat berbasis web memang lebih unggul, tetapi pada 2001 Rx Debugger milik Komodo adalah yang terdepan, dan proyek itu juga sangat menyenangkan untuk dikerjakan
Saya menangani jaringan air-gapped, jadi orang-orang yang perlu memakai alat ini tidak bisa mengakses situs online, dan dalam desain apa pun, memasukkan data kerja ke alat online sama sekali tidak bisa diterima
Namun sebagian besar upaya tampaknya terfokus pada alat online, sementara alat offline jarang dan tertinggal dibandingkan yang seperti https://regex101.com/
Saya penasaran apakah ini bisa dipakai juga pada list, bukan hanya string
Ada perangkat yang kuat untuk mencari dan memodifikasi list karakter, tetapi begitu menjadi list angka atau tanggal, semuanya selalu hilang, dan itu terasa menjengkelkan
Misalnya, jika ingin menemukan semua urutan pada daftar tanggal percobaan login di mana setelah 5 kali atau lebih kegagalan lalu datang keberhasilan, dengan regex itu sederhana, tetapi dalam praktiknya kita harus membuat loop, flag, dan list sementara sendiri
Kita memang bisa mengubah list menjadi string lalu memprosesnya dan mengembalikannya lagi, tetapi kekurangannya sudah jelas. Meski tidak secepat regex berbasis string, saya tidak mengerti kenapa tidak boleh ada regex untuk tipe list arbitrer
Saya juga menemukan prototipe Python yang pernah saya buat dulu: https://github.com/boppreh/listregex
Sangat lambat, tetapi cukup memuaskan sebagai eksperimen API, dan juga menyediakan alat yang tidak ada di regex seperti inversi pola, irisan, dan pencocokan pasangan
Membuat engine regex seperti ini memiliki alfabet generik sejak awal memang terlalu berat. Terutama karena secara realistis sangat sulit dilakukan tanpa merusak desain API dan performa untuk kasus penggunaan utamanya
Engine regex seperti itu yang tidak terlalu memedulikan performa sebenarnya tidak sulit dibuat. Misalnya, Anda bisa mengambil crate
regex-liteyang saya rilis dan mengubahnya menjadi segenerik yang Anda mau, dan dalam prosesnya Anda akan menemui berbagai tantangan menarikBukan berarti hal seperti ini sama sekali tidak ada. Orang-orang pernah mencoba membuatnya[1]. Hanya saja mereka agak melebih-lebihkan kegunaan umumnya, jadi tampaknya biasanya tidak mendapat traction yang besar :-)
[1]: https://docs.rs/automata/latest/automata/trait.Alphabet.html
std::basic_regexdi pustaka standar C++ mencoba pendekatan seperti ini dengan mengekspos kelas templat untuk tipe karakter buatan pengguna: https://en.cppreference.com/w/cpp/regex/basic_regexAnda bisa menyediakan kelas trait yang mendefinisikan perilaku yang dibutuhkan untuk “karakter” buatan pengguna
Namun performanya turun drastis, dan kemungkinan hasilnya hanya akan bekerja sebaik memasukkan objek non-karakter arbitrer ke dalam
std::basic_stringbuatan penggunaIni bukan hal yang mustahil, tetapi kebanyakan bahasa tidak punya antarmuka yang bagus untuk itu
Saya memakai Ripgrep setiap hari saat mencari sesuatu di kode atau file teks, dan setiap kali memakainya di Windows, Linux, Mac, VSCode, atau Vim, saya selalu bersyukur
Ini salah satu perangkat lunak yang mengubah hidup dan cara saya bekerja
Saat terpaksa memakai
grep, rasanya seperti kembali ke masa ketika semua berjalan di CPU satu inti dan datanya ada di hard disk berputar PATA/IDE yang lambatBurntSushi pantas mendapat banyak penghormatan di antara para programmer hebat
ag, dan sebelumnya lagi adaack, dan semuanya berusaha menawarkan antarmuka yang jauh lebih baik daripadagrepbiasaSaya pernah harus membuat
RegexSetdengan lebih dari 10 juta regex untuk masalah pekerjaanTidak ada engine yang mampu menanganinya dalam keadaan default, dan
RegexSetmilik Rust pun tidak cukup dengan pengaturan bawaanMeski begitu, menggunakan
regex-automatadanregex-syntaxsambil membaca kodenya merupakan bahan belajar yang sangat bermanfaat pada 2018Pada akhirnya proyek kerja itu dimodelkan dari API Lucene, tetapi hal itu baru mungkin setelah saya mempelajari dasar-dasarnya dari crate regex
Pekerjaan ke depan adalah membuat engine regex bisa melakukan scale dengan lebih baik untuk lebih banyak pola. Saat ini, ia akan runtuh jauh sebelum 10 juta regex, dan saya pun sulit yakin apakah target itu benar-benar memungkinkan
Meski begitu, jelas masih bisa dibuat lebih baik daripada sekarang
Tentu saja, untuk pencarian multi-pola, Hyperscan pada dasarnya seperti standar emas. Hanya saja saya tidak tahu seberapa baik ia menangani 10 juta pola
Saya pernah bereksperimen dengan crate
regex-automata, dan itu satu-satunya library yang bisa dipakai untuk editor teks karena memberi akses langsung ke DFA internalAPI library regex biasa mengasumsikan inputnya adalah satu string kontinu, tetapi pendekatan ini kompatibel dengan struktur data teks apa pun
Saya sedang menulis kode yang memakai
regex-automata, tepatnya rilisan awal0.2.0, ketika tulisan ini munculSepertinya sudah waktunya memeriksa apakah saya perlu menggali ulang struktur internal yang baru
Saya belum sempat membaca tulisannya, tetapi ini terlihat seperti tulisan yang sangat menarik dengan timing yang pas sekali
Beberapa menit kemudian, jawabannya tampaknya lebih dekat ke “mungkin”, tetapi karena ini rilisan resmi, sepertinya justru bisa sangat menyederhanakan kode saya
Sepuluh menit kemudian lagi, ternyata cukup painless, dan metode
Builder::patchyang baru adalah peningkatan totalSebagai catatan tambahan, saya masih diblokir di semua repositori GitHub Anda, dan mengingat banyak crate Anda dipakai luas, saya rasa itu agak tidak adil. Saya tidak ingat kejadian awalnya. Crate regex itu sendiri tampaknya sekarang berada di bawah organisasi
rust-lang, tetapi masih ada hal-hal yang tidak bisa saya interaksikanregex-automata0.2.0punya peringatan besar tentang ini, dan sangat menyarankan memakai0.1: https://docs.rs/regex-automata/0.2.0/regex_automata/Saya juga tidak ingat kejadian awalnya. Saya memblokir banyak orang karena berbagai alasan, tetapi sekarang blokirnya sudah saya buka
BioJulia merilis Automa.jl, mesin regex murni Julia yang dapat menyisipkan kode Julia arbitrer pada waktu kompilasi
Bukan untuk meremehkan fakta bahwa
regexmilik Rust jauh lebih maju daripada Automa, tetapi saya sulit setuju dengan ungkapan bahwa ini adalah kasus pertama yang mengekspos bagian dalam regex sebagai pustakaMisalnya, PCRE2 memiliki dukungan “callout” yang terdengar mirip dengan yang dimaksud: https://www.pcre.org/current/doc/html/pcre2callout.html
Hal seperti
ragelataure2cjuga sudah melakukan hal serupaYang dibicarakan blog ini adalah mengambil bagian internal dari pustaka regex itu sendiri, menjadikannya pustaka terpisah yang dikelola versinya secara terpisah, lalu memungkinkan orang lain mengombinasikannya
Untuk backtracker, pendekatan ini biasanya kurang alami karena mesinnya umumnya hanya punya satu backtracker, tetapi pustaka berbasis automaton sering menggabungkan beberapa mesin dengan berbagai cara
Meski begitu, bahkan backtracker pun sebenarnya bisa mengekspos hal-hal seperti parser regex atau AST yang biasanya tidak diekspos