2009-06-03 21 views
8

¿Es posible detectar patrones numéricos repetidos con una expresión regular?Expresión regular para detectar la repetición dentro de una cadena

Entonces, por ejemplo, si tuviera la siguiente cadena "034503450345", ¿sería posible hacer coincidir la secuencia repetida 0345? Tengo la sensación de que esto está más allá del alcance de Regex, pero pensé que podría preguntar aquí de todos modos para ver si me he perdido algo.

+1

idioma/plataforma está usando? –

+0

Estoy usando C#. Todo lo que necesitaba era la expresión regular, así que implementé la solución de RichieHindle, ¡y ya lo verifiqué contra mis datos de prueba! También aprendí mucho del regex de Peter Boughton, excelentemente comentado. ¡Gracias a los dos! –

+0

@MarkWithers Estoy lidiando con el mismo problema. ¿Podrías por favor ser más concreto y decirme algo más sobre tu solución? Gracias – user2179427

Respuesta

9

Sí, puede - aquí hay un caso de prueba Python

import re 
print re.search(r"(\d+).*\1", "8034503450345").group(1) 
# Prints 0345 

La expresión regular dice "encontrar alguna secuencia de dígitos, entonces cualquier cantidad de otras cosas, a continuación, la misma secuencia de nuevo."

En una nota casi no-relacionado, aquí está uno de mis expresiones regulares favoritos - un detector de número primo:

import re 
for i in range(2, 100): 
    if not re.search(r"^(xx+)\1+$", "x"*i): 
     print i 
+0

Tu detector de números primos encuentra que 0 y 1 son primos :-) – balpha

+0

Cualquiera ¿por qué el siguiente ejemplo es * solo * que coincide con '8' y no con' 0345'? En [18]: foo = re.search (r "(\ d +) * \ 1", "80345824103452420345") En [19]: foo.groups() Fuera [19]: ('8 ',) –

+0

@balpha: Buen pont - arreglado. 8-) – RichieHindle

19

Esta expresión coincidirá con uno o más grupos que se repiten:

(.+)(?=\1+) 


Aquí está la misma expresión desglosada, (usando el comentario por lo que todavía se puede usar directamente como una expresión regular).

(?x) # enable regex comment mode 
( # start capturing group 
.+ # one or more of any character (excludes newlines by default) 
)  # end capturing group 
(?= # begin lookahead 
\1+ # match one or more of the first capturing group 
)  # end lookahead 


para que coincida con un patrón específico, cambiar el .+ a ese patrón, por ejemplo, \d+ para uno o más números, o \d{4,} para unir 4 o más números.

Para hacer coincidir un número específico del patrón, cambie \1+, por ejemplo, a \1{4} por cuatro repeticiones.

Para permitir que la repetición no esté una al lado de la otra, puede agregar .*? dentro de la búsqueda anticipada.

+1

Gran explicación +1 – ichiban

+0

Buen ejemplo, muy bien explicado –

+0

Gran explicación. Excelente extensión. ¡¡Gracias!! +1 – Toto

8

sólo para añadir una nota de la respuesta (correcta) de RichieHindle:

Tenga en cuenta que si bien la aplicación de expresiones regulares de Python (y muchos otros, como Perl) pueden hacer esto, esto ya no es una expresión regular en el sentido estrecho de la palabra.

Su ejemplo no es un idioma normal, por lo tanto, no puede ser manejado por una expresión regular pura. Ver p. el excelente Wikipedia article para más detalles.

Si bien esto es principalmente solo de interés académico, hay algunas consecuencias prácticas. Las expresiones regulares reales pueden ofrecer mejores garantías para tiempos de ejecución máximos que en este caso. Entonces podrías tener problemas de rendimiento en algún momento.

Por no decir que no es una buena solución, pero debes darte cuenta de que estás al límite de lo que las expresiones regulares (incluso en forma extendida) son capaces de, y querrían considerar otras soluciones en caso de problemas .

+0

Lectura muy interesante, gracias por eso. –

2

Este es el código C#, que usa la construcción de referencia inversa para encontrar dígitos repetidos. Funciona con 034503450345, 123034503450345, 034503450345345, 232034503450345423. La expresión regular es mucho más fácil y clara de entender.

/// <summary> 
/// Assigns repeated digits to repeatedDigits, if the digitSequence matches the pattern 
/// </summary> 
/// <returns>true if success, false otherwise</returns> 
public static bool TryGetRepeatedDigits(string digitSequence, out string repeatedDigits) 
{ 
    repeatedDigits = null; 

    string pattern = @"^\d*(?<repeat>\d+)\k<repeat>+\d*$"; 

    if (Regex.IsMatch(digitSequence, pattern)) 
    { 
     Regex r = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled); 
     repeatedDigits = r.Match(digitSequence).Result("${repeat}"); 
     return true; 
    } 
    else 
     return false; 
} 
+0

¡Muy bonito! Me gusta el uso del grupo nombrado. Código de calidad de producción, comentado y listo para ser copiado. ¡Muchas gracias! –

+0

"Listo para ser copiado": D .. ¡Me gusta eso! –

0

Uso repetición de expresiones regulares: bar {2} mira para el texto con dos o más Bar: barbar barbarbar ...

Cuestiones relacionadas