Saya akan menjelaskan bagian regex di luar pengujian purba: regex berikut ini, diberikan String s
yang 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 \1
serakah).
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 String
panjang n
(diisi dengan yang sama char
)
- Regex menangkap
String
beberapa panjang (katakanlah k
) ke \1
, dan mencoba untuk mencocokkan \1+
dengan sisaString
- Jika ada kecocokan, maka
n
kelipatan yang tepat k
, dan karena n
itu tidak prima.
- Jika tidak ada kecocokan, maka tidak
k
ada yang seperti itu yang membelah n
, dan n
oleh karena itu prima
Bagaimana .?|(..+?)\1+
cocok dengan bilangan prima?
Sebenarnya tidak! Ini cocok String
dengan panjang yang TIDAK prima!
.?
: Bagian pertama dari alternasi cocok String
dengan panjang 0
atau 1
(BUKAN prime dengan definisi)
(..+?)\1+
: Bagian kedua dari pergantian, variasi regex yang dijelaskan di atas, cocok String
dengan panjang n
yang merupakan "kelipatan" String
dari panjang k >= 2
(yaitu n
komposit, BUKAN prima).
- Perhatikan bahwa pengubah enggan
?
sebenarnya tidak diperlukan untuk kebenaran, tetapi dapat membantu mempercepat proses dengan mencoba lebih kecil k
terlebih dahulu
Perhatikan !
boolean
operator pelengkap dalam return
pernyataan: ia meniadakan matches
. Saat regex TIDAK cocok, n
adalah 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 String
panjang n
, diisi dengan yang sama char
,
.{0,1}
memeriksa apakah n = 0,1
, BUKAN prima
(.{2,})\1+
memeriksa apakah n
kelipatan 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+"))
.