J'expliquerai la partie regex en dehors des tests de primalité: la regex suivante, étant donné une String s
qui consiste à répéter String t
, trouve t
.
System.out.println(
"MamamiaMamamiaMamamia".replaceAll("^(.*)\\1+$", "$1")
); // prints "Mamamia"
La façon dont cela fonctionne est que l'expression régulière capture (.*)
dans \1
, puis voit s'il y a une \1+
suite. L'utilisation de ^
et $
garantit qu'une correspondance doit concerner la chaîne entière.
Donc, d'une certaine manière, on nous donne String s
, qui est un "multiple" de String t
, et l'expression rationnelle le trouvera t
(le plus long possible, car il \1
est gourmand).
Une fois que vous avez compris pourquoi cette expression régulière fonctionne, alors (en ignorant la première alternative dans l'expression régulière d'OP pour le moment) expliquer comment elle est utilisée pour les tests de primalité est simple.
- Pour tester la primalité de
n
, commencez par générer un String
de longueur n
(rempli avec le même char
)
- Le regex capture un
String
d'une longueur (disons k
) dans \1
, et essaie de correspondre \1+
au resteString
- S'il y a correspondance, alors
n
est un multiple propre de k
, et n
n'est donc pas premier.
- S'il n'y a pas de correspondance, alors il n'y en a pas
k
qui divise n
, et n
est donc un
Comment faire .?|(..+?)\1+
correspondre les nombres premiers?
En fait, ce n'est pas le cas! Il correspond String
dont la longueur n'est PAS prime!
.?
: La première partie de l'alternance correspond à la String
longueur 0
ou 1
(PAS prime par définition)
(..+?)\1+
: La deuxième partie de l'alternance, une variation de l'expression rationnelle expliquée ci-dessus, correspond à une String
longueur n
qui est "un multiple" de a String
de longueur k >= 2
(c'est n
-à- dire est un composite, PAS un premier).
- Notez que le modificateur réticent
?
n'est en fait pas nécessaire pour l'exactitude, mais il peut aider à accélérer le processus en essayant d' k
abord plus petit
Notez l' !
boolean
opérateur complément dans l' return
instruction: il annule le matches
. C'est quand le regex NE correspond PAS , n
c'est primordial! C'est une logique double négative, donc pas étonnant que ce soit un peu déroutant !!
Simplification
Voici une simple réécriture du code pour le rendre plus lisible:
public static boolean isPrime(int n) {
String lengthN = new String(new char[n]);
boolean isNotPrimeN = lengthN.matches(".?|(..+?)\\1+");
return !isNotPrimeN;
}
Ce qui précède est essentiellement le même que le code Java d'origine, mais divisé en plusieurs instructions avec des affectations à des variables locales pour rendre la logique plus facile à comprendre.
Nous pouvons également simplifier l'expression rationnelle, en utilisant la répétition finie, comme suit:
boolean isNotPrimeN = lengthN.matches(".{0,1}|(.{2,})\\1+");
Encore une fois, étant donné une String
longueurn
, remplie de la même chose char
,
.{0,1}
vérifie si n = 0,1
, PAS amorcer
(.{2,})\1+
vérifie si n
est un multiple correct dek >= 2
, PAS prime
À l'exception du modificateur réticent ?
sur\1
(omis pour plus de clarté), l'expression rationnelle ci - dessus est identique à l'original.
Plus de regex amusant
L'expression régulière suivante utilise une technique similaire; il doit être éducatif:
System.out.println(
"OhMyGod=MyMyMyOhGodOhGodOhGod"
.replaceAll("^(.+)(.+)(.+)=(\\1|\\2|\\3)+$", "$1! $2! $3!")
); // prints "Oh! My! God!"
Voir également
!new String(new char[n]).matches(".?|(..+?)\\1+")
équivaut à!((new String(new char[n])).matches(".?|(..+?)\\1+"))
.