Asallık testinin dışındaki regex kısmını açıklayacağım: aşağıdaki düzenli ifade verilen String s
, yinelemeden oluşan a String t
, bulur t
.
System.out.println(
"MamamiaMamamiaMamamia".replaceAll("^(.*)\\1+$", "$1")
); // prints "Mamamia"
Çalışma şekli, normal ifadenin (.*)
içine girmesi \1
ve ardından \1+
onu takip edip etmediğini görmesidir . kullanılması ^
ve$
sağlayan bir maç bütün dize olması gerektiğini.
Yani, bir bakıma, String s
"çarpanı" olan bize verilir String t
ve normal ifade bunu bulacaktır t
( \1
açgözlü olduğundan mümkün olan en uzun olanı ).
Bu normal ifadenin neden çalıştığını anladıktan sonra (şimdilik OP'nin normal ifadesindeki ilk alternatifi görmezden gelerek), asallık testi için nasıl kullanıldığını açıklamak basittir.
- Asallığını test etmek için
n
, önce bir String
uzunluk oluşturun n
(aynısıyla doldurulmuş char
)
- Normal
String
ifade , k
içine bir miktar (örneğin ) yakalar \1
ve diğeriyle eşleştirmeye çalışır \1+
.String
- Bir eşleşme varsa, o zaman
n
tam katıdır k
ve bu nedenle n
asal değildir.
k
Eşleşme yoksa bölen böyle bir şey yoktur n
ve n
bu nedenle asal
.?|(..+?)\1+
Asal sayılarla nasıl eşleşir?
Aslında öyle değil! Bu maçları String
uzunluğu DEĞİL asal!
.?
: Değişimli String
uzunluk eşleşmelerinin ilk bölümü 0
veya 1
(tanım gereği asal DEĞİL)
(..+?)\1+
: Sırayla değişen ikinci kısmı, düzenli ifade bir varyasyonu, yukarıda açıklandığı gibi, stoktaki String
uzunluğunun n
içinde bir "çoklu" olduğu String
uzunluğunun k >= 2
(diğer bir deyişlen
bileşik, değil bir asal).
- İsteksiz değiştiricinin
?
aslında doğruluk için gerekli olmadığını, ancak k
önce daha küçük deneyerek süreci hızlandırmaya yardımcı olabileceğini unutmayın.
Not !
boolean
içinde tamamlayıcı operatörü return
açıklamada: değilleme matches
. Regex zaman var ETMEZ maç, n
asal! Bu ikili negatif bir mantık, bu yüzden kafa karıştırıcı olmasına şaşmamalı !!
sadeleştirme
İşte kodu daha okunaklı hale getirmek için basit bir yeniden yazma:
public static boolean isPrime(int n) {
String lengthN = new String(new char[n]);
boolean isNotPrimeN = lengthN.matches(".?|(..+?)\\1+");
return !isNotPrimeN;
}
Yukarıdakiler esasen orijinal Java koduyla aynıdır, ancak mantığın anlaşılmasını kolaylaştırmak için yerel değişkenlere atamalarla birden çok ifadeye bölünmüştür.
Ayrıca, aşağıdaki gibi, sonlu tekrar kullanarak normal ifadeyi basitleştirebiliriz:
boolean isNotPrimeN = lengthN.matches(".{0,1}|(.{2,})\\1+");
Yine, bir String
uzunluk verildiğinde n
, aynısı ile dolu char
,
.{0,1}
kontrol eder n = 0,1
, asal DEĞİL
(.{2,})\1+
asal DEĞİL, n
doğru bir katı olup olmadığını kontrol ederk >= 2
İsteksiz değiştiricinin ?
açık olması dışında \1
(açıklık amacıyla atlanmıştır), yukarıdaki normal ifade orijinal ile aynıdır.
Daha eğlenceli normal ifade
Aşağıdaki normal ifade benzer bir teknik kullanır; eğitici olmalı:
System.out.println(
"OhMyGod=MyMyMyOhGodOhGodOhGod"
.replaceAll("^(.+)(.+)(.+)=(\\1|\\2|\\3)+$", "$1! $2! $3!")
); // prints "Oh! My! God!"
Ayrıca bakınız
!new String(new char[n]).matches(".?|(..+?)\\1+")
eşdeğerdir!((new String(new char[n])).matches(".?|(..+?)\\1+"))
.