Encontré el siguiente ejemplo de código para Java en RosettaCode :
public static boolean prime(int n) {
return !new String(new char[n]).matches(".?|(..+?)\\1+");
}
- No conozco Java en particular, pero entiendo todos los aspectos de este fragmento, excepto la expresión regular en sí.
- Tengo conocimiento básico a básico-avanzado de Regex tal como lo encuentra en las funciones integradas de PHP
¿Cómo .?|(..+?)\\1+coincide los números primos?

!new String(new char[n]).matches(".?|(..+?)\\1+")es equivalente a!((new String(new char[n])).matches(".?|(..+?)\\1+")).Respuestas:
Dijiste que entiendes esta parte, pero solo para enfatizar, la cadena generada tiene una longitud igual al número proporcionado. Entonces la cadena tiene tres caracteres si y solo si
n == 3.La primera parte de la expresión regular dice: "cualquier carácter, cero o una vez". Así que, básicamente, no es cero o uno o character--, por lo que he mencionado anteriormente,
n == 0 || n == 1. Si tenemos el partido, entonces devuelve la negación de eso. Esto corresponde con el hecho de que cero y uno NO son primos.La segunda parte de la expresión regular es un poco más complicada, ya que depende de grupos y referencias. Un grupo es cualquier cosa entre paréntesis, que luego será capturado y almacenado por el motor de expresiones regulares para su uso posterior. Una referencia inversa es un grupo coincidente que se usa más adelante en la misma expresión regular.
El grupo captura 1 personaje, luego 1 o más de cualquier personaje. (El carácter + significa uno o más, pero SOLO del carácter o grupo anterior. Por lo tanto, no se trata de "dos o cuatro o seis caracteres, etc.", sino más bien "dos o tres, etc." El +? Es como +, pero intenta hacer coincidir la menor cantidad posible de caracteres. + normalmente intenta engullir toda la cadena si puede, lo cual es malo en este caso porque evita que la parte de referencia inversa funcione).
La siguiente parte es la referencia: ese mismo conjunto de caracteres (dos o más), que aparecen nuevamente. Dicha referencia aparece una o más veces.
Entonces. El grupo capturado corresponde a un número natural de caracteres (de 2 en adelante) capturados. Dicho grupo aparece entonces un número natural de veces (también de 2 en adelante). Si hay una coincidencia, esto implica que es posible encontrar un producto de dos números mayor o igual a 2 que coincida con la cadena de longitud n ... lo que significa que tiene una n compuesta. Entonces, nuevamente, devuelva la negación de la coincidencia exitosa: n NO es primo.
Si no se puede encontrar una coincidencia, entonces no puede obtener un producto de dos números naturales mayores o iguales a 2 ... y tiene tanto una no coincidencia como un primo, por lo tanto, nuevamente el retorno de la negación del resultado del partido.
lo ves ahora? Es increíblemente complicado (¡y computacionalmente costoso!) Pero también es algo simple al mismo tiempo, una vez que lo obtienes. :-)
Puedo elaborar si tiene más preguntas, como sobre cómo funciona realmente el análisis de expresiones regulares. Pero estoy tratando de mantener esta respuesta simple por ahora (o lo más simple posible).
fuente
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 repetirString t, encuentrat.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" deString t, y la expresión regular encontrará talt(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.
n, primero genere unStringde longitudn(rellenado con el mismochar)Stringpoco de longitud (digamosk)\1e intenta hacer coincidir\1+con el resto de laStringnes un múltiplo adecuado deky, pornlo tanto, no es primo.kexiste tal cosa que se dividany,npor lo tanto , sea primordialEn realidad, no lo hace! ¡ Coincide con la
Stringlongitud que NO es primo!.?: La primera parte de las coincidenciasStringde alternancia de longitud0o1(NO primo por definición)(..+?)\1+: La segunda parte de la alternancia, una variación de la expresión regular explicada anteriormente, coincide con laStringlongitudnque es "un múltiplo" de unaStringlongitudk >= 2(nes decir, es un compuesto, NO un primo).?no es realmente necesario para la corrección, pero puede ayudar a acelerar el proceso al intentarkprimero más pequeñoTenga en cuenta el
!booleanoperador de complemento en lareturndeclaración: niega elmatches. 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:
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:
De nuevo, dado un
Stringlargon, lleno de lo mismochar,.{0,1}comprueba sin = 0,1, NO cebar(.{2,})\1+comprueba sines un múltiplo adecuado dek >= 2, NO cebarCon 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:
Ver también
fuente
[Populist]algún día de esto.Buen truco regex (aunque muy ineficiente) ... :)
La expresión regular define los no primos de la siguiente manera:
N no es primo si y solo si N <= 1 O N es divisible por alguna K> 1.
En lugar de pasar la simple representación digital de N al motor de expresiones regulares, se alimenta con una secuencia de longitud N, compuesta de un carácter repetitivo. La primera parte de la disyunción verifica N = 0 o N = 1, y la segunda busca un divisor K> 1, utilizando referencias posteriores. Obliga al motor regex a encontrar alguna subsecuencia no vacía que se puede repetir al menos dos veces para formar la secuencia. Si existe tal subsecuencia, significa que su longitud divide N, por lo tanto, N no es primo.
fuente
Aplicar a los números después de la conversión a la base 1 (1 = 1, 2 = 11, 3 = 111, ...). Los no primos coincidirán con esto. Si no coincide, es primo.
Explicación aquí .
fuente