Explicaré la parte de la expresión regular fuera de la prueba de primalidad: la siguiente expresión regular, dada una String s
que consiste en repetir String t
, encuentra t
.
System.out.println(
"MamamiaMamamiaMamamia".replaceAll("^(.*)\\1+$", "$1")
); // prints "Mamamia"
La forma en que funciona es que las capturas de expresiones regulares (.*)
en \1
, y luego ve si hay \1+
tras ella. El uso de ^
y $
asegura que una coincidencia debe ser de toda la cadena.
Entonces, en cierto modo, se nos da String s
, que es un "múltiplo" de String t
, y la expresión regular encontrará tal t
(el más largo posible, ya que \1
es codicioso).
Una vez que comprenda por qué funciona esta expresión regular, entonces (ignorando la primera alternativa en la expresión regular de OP por ahora) explicando cómo se usa para la prueba de primalidad es simple.
- Para probar la primalidad de
n
, primero genere un String
de longitud n
(rellenado con el mismo char
)
- La expresión regular captura un
String
poco de longitud (digamos k
) \1
e intenta hacer coincidir \1+
con el resto de laString
- Si hay una coincidencia, entonces
n
es un múltiplo adecuado de k
y, por n
lo tanto, no es primo.
- Si no hay coincidencia, entonces no
k
existe tal cosa que se divida n
y, n
por lo tanto , sea primordial
¿Cómo .?|(..+?)\1+
coincide los números primos?
En realidad, no lo hace! ¡ Coincide con la String
longitud que NO es primo!
.?
: La primera parte de las coincidencias String
de alternancia de longitud 0
o 1
(NO primo por definición)
(..+?)\1+
: La segunda parte de la alternancia, una variación de la expresión regular explicada anteriormente, coincide con la String
longitud n
que es "un múltiplo" de una String
longitud k >= 2
( n
es decir, es un compuesto, NO un primo).
- Tenga en cuenta que el modificador reacio
?
no es realmente necesario para la corrección, pero puede ayudar a acelerar el proceso al intentar k
primero más pequeño
Tenga en cuenta el !
boolean
operador de complemento en la return
declaración: niega el matches
. Es cuando la expresión regular NO coincide, ¡ n
es primordial! Es una lógica doblemente negativa, ¡así que no es de extrañar que sea un poco confuso!
Simplificación
Aquí hay una reescritura simple del código para hacerlo más legible:
public static boolean isPrime(int n) {
String lengthN = new String(new char[n]);
boolean isNotPrimeN = lengthN.matches(".?|(..+?)\\1+");
return !isNotPrimeN;
}
Lo anterior es esencialmente el mismo que el código Java original, pero se divide en varias declaraciones con asignaciones a variables locales para facilitar la comprensión de la lógica.
También podemos simplificar la expresión regular, utilizando la repetición finita, de la siguiente manera:
boolean isNotPrimeN = lengthN.matches(".{0,1}|(.{2,})\\1+");
De nuevo, dado un String
largo n
, lleno de lo mismo char
,
.{0,1}
comprueba si n = 0,1
, NO cebar
(.{2,})\1+
comprueba si n
es un múltiplo adecuado de k >= 2
, NO cebar
Con la excepción del modificador reacios ?
en \1
(omitido para mayor claridad), la expresión regular anterior es idéntica a la original.
Más diversión regex
La siguiente expresión regular utiliza una técnica similar; debería ser educativo:
System.out.println(
"OhMyGod=MyMyMyOhGodOhGodOhGod"
.replaceAll("^(.+)(.+)(.+)=(\\1|\\2|\\3)+$", "$1! $2! $3!")
); // prints "Oh! My! God!"
Ver también
!new String(new char[n]).matches(".?|(..+?)\\1+")
es equivalente a!((new String(new char[n])).matches(".?|(..+?)\\1+"))
.