Gambaran Keseluruhan Prestasi Ekspresi Biasa di Jawa

1. Gambaran keseluruhan

Dalam tutorial ringkas ini, kami akan menunjukkan bagaimana mesin pemadan corak berfungsi. Kami juga akan memberikan cara yang berbeza untuk mengoptimumkan ungkapan biasa di Java.

Untuk pengenalan mengenai penggunaan ungkapan biasa , rujuk artikel ini di sini.

2. Mesin Pencocokan Corak

The java.util.regex pakej menggunakan sejenis enjin pemadanan corak dipanggil nondeterministic terhingga Automaton (NFA). Ini dianggap tidak menentu kerana ketika mencoba mencocokkan ekspresi biasa pada rentetan tertentu, setiap karakter dalam input mungkin diperiksa beberapa kali terhadap berbagai bagian dari ekspresi biasa.

Di latar belakang, enjin yang disebutkan di atas menggunakan backtracking . Algoritma umum ini cuba menghabiskan semua kemungkinan sehingga menyatakan kegagalan. Pertimbangkan contoh berikut untuk lebih memahami NFA :

"tra(vel|ce|de)m"

Dengan input String " travel ", mesin pertama akan mencari " tra " dan segera mencarinya.

Selepas itu, ia akan mencocokkan " vel " bermula dari watak keempat. Ini akan sesuai, jadi ia akan maju dan mencocokkan " m ".

Itu tidak akan sesuai, dan untuk alasan itu, ia akan kembali ke watak keempat dan mencari " ce ". Sekali lagi, ini tidak akan sesuai, jadi akan kembali lagi ke kedudukan keempat dan mencuba dengan " de ". Rentetan itu tidak akan sepadan, dan ia akan kembali ke watak kedua dalam rentetan input dan cuba mencari " tra " yang lain.

Dengan kegagalan terakhir, algoritma akan mengembalikan kegagalan.

Dengan contoh terakhir yang mudah, mesin terpaksa mundur beberapa kali sambil mencocokkan input String dengan ungkapan biasa. Oleh kerana itu, penting untuk meminimumkan jumlah backtracking yang dilakukannya.

3. Cara Mengoptimumkan Ungkapan Biasa

3.1. Elakkan Penyusunan Semula

Ungkapan biasa di Java disusun menjadi struktur data dalaman. Penyusunan ini adalah proses yang memakan masa.

Setiap kali kita menggunakan kaedah String.matches (String regex) , ungkapan biasa yang ditentukan dikompilasi ulang:

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

Seperti yang kita lihat, setiap kali keadaan dinilai, ungkapan regex disusun.

Untuk mengoptimumkan, mungkin untuk menyusun corak terlebih dahulu dan kemudian membuat Matcher untuk mencari kebetulan dalam nilai:

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

Alternatif untuk pengoptimuman di atas adalah menggunakan instance Matcher yang sama dengan kaedah reset () :

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

Kerana fakta bahawa Matcher tidak selamat dalam benang, kita harus berhati-hati dengan penggunaan variasi ini. Ia mungkin berbahaya dalam senario berbilang benang.

Ringkasnya, dalam setiap situasi di mana kami yakin hanya ada satu pengguna Matcher pada suatu saat, tidak mengapa menggunakannya semula dengan reset . Selebihnya, menggunakan semula kompilasi sudah cukup.

3.2. Bekerja dengan Alternatif

Seperti yang baru kita periksa di bahagian terakhir, penggunaan penggantian yang tidak mencukupi boleh memudaratkan prestasi. Penting untuk meletakkan pilihan yang kemungkinan besar berlaku di bahagian depan supaya mereka dapat dipadankan dengan lebih cepat.

Kita juga mesti mengekstrak corak umum di antara mereka. Tidak sama dengan meletakkan:

(travel | trade | trace)

Daripada:

tra(vel | de | ce)

Yang terakhir ini lebih pantas kerana NFA akan mencocokkan " tra " dan tidak akan mencuba salah satu alternatif jika tidak menemukannya.

3.3. Menangkap Kumpulan

Setiap kali kita menangkap kumpulan, kita akan dikenakan hukuman kecil-kecil.

Sekiranya kita tidak perlu menangkap teks di dalam kumpulan, kita harus mempertimbangkan penggunaan kumpulan yang tidak menangkap. Daripada menggunakan " (M) ", tolong gunakan " (?: M) ".

4. Kesimpulan

Dalam artikel ringkas ini, kami meninjau secara ringkas bagaimana NFA berfungsi. Kami kemudian terus meneroka cara mengoptimumkan prestasi ungkapan biasa kami dengan menyusun semula corak kami dan menggunakan semula Matcher .

Akhirnya, kami menunjukkan beberapa pertimbangan yang perlu diingat semasa kami bekerja dengan penggantian dan kumpulan.

Seperti biasa, kod sumber lengkap boleh didapati di GitHub.