Saya akan menjelaskan bagian regex di luar pengujian purba: regex berikut ini, diberikan String syang terdiri dari pengulangan String t, penemuan t.
System.out.println(
"MamamiaMamamiaMamamia".replaceAll("^(.*)\\1+$", "$1")
); // prints "Mamamia"
Cara kerjanya adalah bahwa menangkap regex (.*)ke \1, dan kemudian melihat apakah ada yang \1+mengikutinya. Menggunakan ^dan $memastikan bahwa kecocokan harus dari keseluruhan string.
Jadi, dengan cara tertentu, kita diberikan String s, yang merupakan "kelipatan" dari String t, dan regex akan menemukan itu t(paling lama mungkin, karena \1serakah).
Setelah Anda memahami mengapa regex ini bekerja, maka (mengabaikan alternatif pertama dalam regex OP untuk saat ini) menjelaskan bagaimana ini digunakan untuk pengujian primality sederhana.
- Untuk menguji keutamaan
n, pertama-tama hasilkan Stringpanjang n(diisi dengan yang sama char)
- Regex menangkap
Stringbeberapa panjang (katakanlah k) ke \1, dan mencoba untuk mencocokkan \1+dengan sisaString
- Jika ada kecocokan, maka
nkelipatan yang tepat k, dan karena nitu tidak prima.
- Jika tidak ada kecocokan, maka tidak
kada yang seperti itu yang membelah n, dan noleh karena itu prima
Bagaimana .?|(..+?)\1+cocok dengan bilangan prima?
Sebenarnya tidak! Ini cocok String dengan panjang yang TIDAK prima!
.?: Bagian pertama dari alternasi cocok Stringdengan panjang 0atau 1(BUKAN prime dengan definisi)
(..+?)\1+: Bagian kedua dari pergantian, variasi regex yang dijelaskan di atas, cocok Stringdengan panjang nyang merupakan "kelipatan" Stringdari panjang k >= 2(yaitu nkomposit, BUKAN prima).
- Perhatikan bahwa pengubah enggan
?sebenarnya tidak diperlukan untuk kebenaran, tetapi dapat membantu mempercepat proses dengan mencoba lebih kecil kterlebih dahulu
Perhatikan ! booleanoperator pelengkap dalam returnpernyataan: ia meniadakan matches. Saat regex TIDAK cocok, nadalah yang utama! Ini logika ganda-negatif, jadi tidak heran itu agak membingungkan !!
Penyederhanaan
Berikut adalah penulisan ulang kode yang sederhana agar lebih mudah dibaca:
public static boolean isPrime(int n) {
String lengthN = new String(new char[n]);
boolean isNotPrimeN = lengthN.matches(".?|(..+?)\\1+");
return !isNotPrimeN;
}
Di atas pada dasarnya sama dengan kode Java asli, tetapi dipecah menjadi beberapa pernyataan dengan penugasan ke variabel lokal untuk membuat logika lebih mudah dimengerti.
Kami juga dapat menyederhanakan regex, menggunakan pengulangan terbatas, sebagai berikut:
boolean isNotPrimeN = lengthN.matches(".{0,1}|(.{2,})\\1+");
Sekali lagi, diberi Stringpanjang n, diisi dengan yang sama char,
.{0,1}memeriksa apakah n = 0,1, BUKAN prima
(.{2,})\1+memeriksa apakah nkelipatan yang tepat k >= 2, BUKAN prima
Dengan pengecualian pengubah enggan ?aktif \1(dihilangkan untuk kejelasan), regex di atas identik dengan aslinya.
Regex lebih menyenangkan
Regex berikut menggunakan teknik serupa; itu harus mendidik:
System.out.println(
"OhMyGod=MyMyMyOhGodOhGodOhGod"
.replaceAll("^(.+)(.+)(.+)=(\\1|\\2|\\3)+$", "$1! $2! $3!")
); // prints "Oh! My! God!"
Lihat juga
!new String(new char[n]).matches(".?|(..+?)\\1+")setara dengan!((new String(new char[n])).matches(".?|(..+?)\\1+")).