Gambaran Umum Performa Ekspresi Reguler di Java

1. Ikhtisar

Dalam tutorial singkat ini, kami akan menunjukkan cara kerja mesin pencocokan pola. Kami juga akan menyajikan berbagai cara untuk mengoptimalkan ekspresi reguler di Java.

Untuk pengantar penggunaan ekspresi reguler , lihat artikel ini di sini.

2. Mesin Pencocokan Pola

The java.util.regex paket menggunakan tipe mesin pencocokan pola disebut Nondeterministic Finite Automata (NFA). Ini dianggap nondeterministik karena saat mencoba mencocokkan ekspresi reguler pada string tertentu, setiap karakter dalam masukan mungkin diperiksa beberapa kali terhadap bagian berbeda dari ekspresi reguler.

Di latar belakang, mesin yang disebutkan di atas menggunakan jalur mundur . Algoritme umum ini mencoba untuk menghabiskan semua kemungkinan hingga menyatakan kegagalan. Pertimbangkan contoh berikut untuk lebih memahami NFA :

"tra(vel|ce|de)m"

Dengan input String " travel ", mesin akan mencari " tra " terlebih dahulu dan segera menemukannya.

Setelah itu akan dicocokkan dengan “ vel ” mulai dari karakter keempat. Ini akan cocok, jadi akan maju dan mencoba untuk mencocokkan " m ".

Itu tidak akan cocok, dan untuk alasan itu, itu akan kembali ke karakter keempat dan mencari " ce ". Sekali lagi, ini tidak akan cocok, jadi akan kembali lagi ke posisi keempat dan coba dengan " de ". String itu juga tidak akan cocok, sehingga akan kembali ke karakter kedua dalam string input dan mencoba mencari " tra " lainnya.

Dengan kegagalan terakhir, algoritme akan mengembalikan kegagalan.

Dengan contoh terakhir yang sederhana, mesin harus mundur beberapa kali saat mencoba mencocokkan string masukan ke ekspresi reguler. Karena itu, penting untuk meminimalkan jumlah kemunduran yang dilakukannya.

3. Cara Mengoptimalkan Ekspresi Reguler

3.1. Hindari Kompilasi Ulang

Ekspresi reguler di Java dikompilasi menjadi struktur data internal. Kompilasi ini adalah proses yang memakan waktu.

Setiap kali kita memanggil metode String.matches (String regex) , ekspresi reguler yang ditentukan dikompilasi ulang:

if (input.matches(regexPattern)) { // do something }

Seperti yang bisa kita lihat, setiap kali kondisi dievaluasi, ekspresi regex dikompilasi.

Untuk mengoptimalkan, dimungkinkan untuk mengkompilasi pola terlebih dahulu dan kemudian membuat Matcher untuk menemukan kebetulan dalam nilainya:

Pattern pattern = Pattern.compile(regexPattern); for(String value : values) { Matcher matcher = pattern.matcher(value); if (matcher.matches()) { // do something } }

Alternatif untuk pengoptimalan di atas menggunakan instance Matcher yang sama dengan metode reset () :

Pattern pattern = Pattern.compile(regexPattern); Matcher matcher = pattern.matcher(""); for(String value : values) { matcher.reset(value); if (matcher.matches()) { // do something } }

Karena fakta bahwa Matcher tidak aman untuk thread, kita harus berhati-hati dengan penggunaan variasi ini. Ini mungkin berbahaya dalam skenario multi-utas.

Untuk meringkas, dalam setiap situasi di mana kami yakin hanya ada satu pengguna Matcher pada suatu saat, tidak masalah untuk menggunakannya kembali dengan reset . Selebihnya, menggunakan kembali precompiled saja sudah cukup.

3.2. Bekerja dengan Bergantian

Seperti yang baru saja kita periksa di bagian terakhir, penggunaan pergantian yang tidak memadai dapat merusak kinerja. Penting untuk menempatkan opsi yang lebih mungkin terjadi di depan sehingga bisa dicocokkan lebih cepat.

Juga, kita harus mengekstrak pola umum di antara mereka. Ini tidak sama dengan mengatakan:

(travel | trade | trace)

Dari:

tra(vel | de | ce)

Yang terakhir ini lebih cepat karena NFA akan mencoba untuk mencocokkan " tra " dan tidak akan mencoba salah satu alternatif jika tidak menemukannya.

3.3. Menangkap Grup

Setiap kali kami menangkap grup, kami mendapat penalti kecil.

Jika kita tidak perlu menangkap teks di dalam grup, kita harus mempertimbangkan penggunaan grup non-penangkapan. Daripada menggunakan " (M) ", harap gunakan " (?: M) ".

4. Kesimpulan

Dalam artikel singkat ini, kami meninjau kembali secara singkat cara kerja NFA . Kami kemudian melanjutkan untuk menjelajahi cara mengoptimalkan kinerja ekspresi reguler kami dengan menyusun pola kami sebelumnya dan menggunakan kembali Matcher .

Akhirnya, kami menunjukkan beberapa pertimbangan yang perlu diingat saat kami bekerja dengan pergantian dan kelompok.

Seperti biasa, kode sumber lengkap dapat ditemukan di GitHub.