Wyjaśnię część wyrażenia regularnego poza testowaniem pierwszości: następujący wyrażenie regularne, biorąc pod uwagę a, String s
które składa się z powtarzania String t
, znajduje t
.
System.out.println(
"MamamiaMamamiaMamamia".replaceAll("^(.*)\\1+$", "$1")
);
Sposób działania polega na tym, że wyrażenie regularne przechwytuje (.*)
do \1
, a następnie sprawdza, czy \1+
następuje po nim. Korzystanie z ^
i$
gwarantuje, że dopasowanie musi obejmować cały ciąg.
Tak więc, w pewnym sensie, otrzymujemy String s
, co jest „wielokrotnością” String t
, a wyrażenie regularne takie znajdzie t
(najdłuższe możliwe, ponieważ \1
jest chciwe).
Kiedy zrozumiesz, dlaczego to wyrażenie regularne działa, to (pomijając na razie pierwszą alternatywę w wyrażeniu regularnym OP) wyjaśnienie, w jaki sposób jest używane do testowania pierwszości, jest proste.
- Aby przetestować pierwszorzędność
n
, najpierw wygeneruj String
długość n
(wypełnioną tym samymchar
)
- Wyrażenie regularne przechwytuje a
String
o pewnej długości (powiedzmy k
) do \1
i próbuje dopasować \1+
do resztyString
- Jeśli jest dopasowanie, to
n
jest właściwą wielokrotnością k
i dlatego n
nie jest liczbą pierwszą.
- Jeśli nie ma dopasowania, to nie
k
istnieje coś takiego , co dzieli n
i n
dlatego jest liczbą pierwszą
Jak wygląda .?|(..+?)\1+
dopasowanie liczb pierwszych?
Właściwie tak nie jest! To pasuje String
, którego długość wynosi NIE prime!
.?
: Pierwsza część naprzemiennych dopasowań String
długości 0
lub 1
(z definicji NIE jest pierwsza)
(..+?)\1+
: Druga część przemienności, odmiana wyrażenia regularnego wyjaśniona powyżej, dopasowania String
długości, n
które są „wielokrotnością” String
długości a k >= 2
(tj.n
Jest złożeniem, a NIE liczbą pierwszą).
- Zauważ, że niechętny modyfikator w
?
rzeczywistości nie jest potrzebny do poprawności, ale może pomóc przyspieszyć proces, próbując k
najpierw użyć mniejszego
Zwróć uwagę na !
boolean
operator dopełniacza w return
instrukcji: neguje on matches
. Dzieje się tak, gdy wyrażenie regularne NIE pasuje, n
jest liczbą pierwszą! To logika podwójnie ujemna, więc nic dziwnego, że jest trochę myląca!
Uproszczenie
Oto proste przepisanie kodu, aby był bardziej czytelny:
public static boolean isPrime(int n) {
String lengthN = new String(new char[n]);
boolean isNotPrimeN = lengthN.matches(".?|(..+?)\\1+");
return !isNotPrimeN;
}
Powyższe jest zasadniczo takie samo, jak oryginalny kod Java, ale podzielone na wiele instrukcji z przypisaniami do zmiennych lokalnych, aby ułatwić zrozumienie logiki.
Możemy również uprościć wyrażenie regularne, używając skończonych powtórzeń, w następujący sposób:
boolean isNotPrimeN = lengthN.matches(".{0,1}|(.{2,})\\1+");
Ponownie, biorąc String
pod uwagę długość n
, wypełniony tym samym char
,
.{0,1}
sprawdza, czy n = 0,1
NIE jest pierwsza
(.{2,})\1+
sprawdza, czy n
jest poprawną wielokrotnością k >= 2
, a nie liczbą pierwszą
Z wyjątkiem niechętnego modyfikatora ?
włączonego \1
(pominiętego dla przejrzystości), powyższe wyrażenie regularne jest identyczne z oryginałem.
Bardziej zabawne wyrażenie regularne
Poniższe wyrażenie regularne używa podobnej techniki; powinien być edukacyjny:
System.out.println(
"OhMyGod=MyMyMyOhGodOhGodOhGod"
.replaceAll("^(.+)(.+)(.+)=(\\1|\\2|\\3)+$", "$1! $2! $3!")
);
Zobacz też
!new String(new char[n]).matches(".?|(..+?)\\1+")
jest odpowiednikiem!((new String(new char[n])).matches(".?|(..+?)\\1+"))
.