Wyjaśnię część wyrażenia regularnego poza testowaniem pierwszości: następujący wyrażenie regularne, biorąc pod uwagę a, String sktó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ż \1jest 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 Stringdługość n(wypełnioną tym samymchar )
- Wyrażenie regularne przechwytuje a
Stringo pewnej długości (powiedzmy k) do \1i próbuje dopasować \1+do resztyString
- Jeśli jest dopasowanie, to
njest właściwą wielokrotnością ki dlatego nnie jest liczbą pierwszą.
- Jeśli nie ma dopasowania, to nie
kistnieje coś takiego , co dzieli ni ndlatego 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ń Stringdługości 0lub 1(z definicji NIE jest pierwsza)
(..+?)\1+: Druga część przemienności, odmiana wyrażenia regularnego wyjaśniona powyżej, dopasowania Stringdługości, nktóre są „wielokrotnością” Stringdł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 knajpierw użyć mniejszego
Zwróć uwagę na ! booleanoperator dopełniacza w returninstrukcji: neguje on matches. Dzieje się tak, gdy wyrażenie regularne NIE pasuje, njest 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 Stringpod uwagę długość n, wypełniony tym samym char,
.{0,1}sprawdza, czy n = 0,1NIE jest pierwsza
(.{2,})\1+sprawdza, czy njest 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+")).