Explicaré la parte de la expresión regular fuera de la prueba de primalidad: la siguiente expresión regular, dada una String sque 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 \1es 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 Stringde longitud n(rellenado con el mismo char)
- La expresión regular captura un
Stringpoco de longitud (digamos k) \1e intenta hacer coincidir \1+con el resto de laString
- Si hay una coincidencia, entonces
nes un múltiplo adecuado de ky, por nlo tanto, no es primo.
- Si no hay coincidencia, entonces no
kexiste tal cosa que se divida ny, npor 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 Stringde alternancia de longitud 0o 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 Stringlongitud nque es "un múltiplo" de una Stringlongitud k >= 2( nes 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 kprimero más pequeño
Tenga en cuenta el ! booleanoperador de complemento en la returndeclaración: niega el matches. Es cuando la expresión regular NO coincide, ¡ nes 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 Stringlargo n, lleno de lo mismo char,
.{0,1}comprueba si n = 0,1, NO cebar
(.{2,})\1+comprueba si nes 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+")).