Ich werde den Regex-Teil außerhalb des Primalitätstests erklären: Der folgende Regex, der a gegeben ist String s
und aus Wiederholungen besteht String t
, findet t
.
System.out.println(
"MamamiaMamamiaMamamia".replaceAll("^(.*)\\1+$", "$1")
); // prints "Mamamia"
Das System funktioniert so , dass die Regex Aufnahmen (.*)
in \1
und sieht dann , wenn es \1+
danach. Die Verwendung von ^
und $
stellt sicher, dass eine Übereinstimmung mit der gesamten Zeichenfolge bestehen muss.
In gewisser Weise erhalten wir String s
also ein "Vielfaches" von String t
, und der Regex wird ein solches finden t
(das längste, da \1
es gierig ist).
Sobald Sie verstanden haben, warum dieser reguläre Ausdruck funktioniert, ist es einfach, die erste Alternative im regulären Ausdruck des OP zu ignorieren und zu erklären, wie er für Primalitätstests verwendet wird.
- Um die Primalität von zu testen
n
, generieren Sie zuerst eine String
Länge n
(gefüllt mit derselben char
).
- Der Regex erfasst eine
String
Länge von (sagen wir k
) in \1
und versucht, \1+
mit dem Rest des zu übereinstimmenString
- Wenn es eine Übereinstimmung gibt, dann
n
ist ein richtiges Vielfaches von k
und ist daher n
keine Primzahl.
- Wenn es keine Übereinstimmung gibt, gibt es keine solche
k
, die sich teilt n
und n
daher eine Primzahl ist
Wie .?|(..+?)\1+
stimmen Primzahlen überein?
Eigentlich nicht! Es passt zu String
dessen Länge NICHT prim ist!
.?
: Der erste Teil des Wechsels entspricht String
der Länge 0
oder 1
(per Definition NICHT prim)
(..+?)\1+
: Der zweite Teil des Wechsels, eine Variation des oben erläuterten regulären Ausdrucks, entspricht String
einer Länge n
, die "ein Vielfaches" einer String
Länge ist k >= 2
(dh n
eine zusammengesetzte, keine Primzahl).
- Beachten Sie, dass das nur ungern Modifikator
?
ist eigentlich nicht für Richtigkeit benötigt, aber es kann beschleunigen den Prozess helfen , indem sie kleinere versuchen k
zuerst
Beachten Sie den !
boolean
Komplementoperator in der return
Anweisung: Er negiert den matches
. Es ist, wenn der Regex NICHT übereinstimmt, n
ist Prime! Es ist eine doppelt negative Logik, also kein Wunder, dass es irgendwie verwirrend ist !!
Vereinfachung
Hier ist eine einfache Neufassung des Codes, um ihn besser lesbar zu machen:
public static boolean isPrime(int n) {
String lengthN = new String(new char[n]);
boolean isNotPrimeN = lengthN.matches(".?|(..+?)\\1+");
return !isNotPrimeN;
}
Das Obige ist im Wesentlichen dasselbe wie der ursprüngliche Java-Code, jedoch in mehrere Anweisungen mit Zuweisungen zu lokalen Variablen unterteilt, um das Verständnis der Logik zu erleichtern.
Wir können den regulären Ausdruck auch durch endliche Wiederholung wie folgt vereinfachen:
boolean isNotPrimeN = lengthN.matches(".{0,1}|(.{2,})\\1+");
Wieder gegeben, gegeben von einer String
Länge n
, gefüllt mit dem gleichen char
,
.{0,1}
prüft ob n = 0,1
, NICHT grundieren
(.{2,})\1+
prüft, ob n
es sich um ein richtiges Vielfaches von handelt k >= 2
, NICHT um eine Primzahl
Mit Ausnahme des nur ungern Modifikator ?
auf \1
(aus Gründen der Übersichtlichkeit weggelassen), ist die obige regex identisch mit dem Original.
Mehr Spaß Regex
Der folgende reguläre Ausdruck verwendet eine ähnliche Technik. es sollte lehrreich sein:
System.out.println(
"OhMyGod=MyMyMyOhGodOhGodOhGod"
.replaceAll("^(.+)(.+)(.+)=(\\1|\\2|\\3)+$", "$1! $2! $3!")
); // prints "Oh! My! God!"
Siehe auch
!new String(new char[n]).matches(".?|(..+?)\\1+")
entspricht!((new String(new char[n])).matches(".?|(..+?)\\1+"))
.