Regex para eliminar el patrón de caracteres repetidos en una cadena

Tengo una cadena que puede tener un patrón de caracteres repetido, por ejemplo,

'xyzzyxxyzzyxxyzzyx' 

Necesito escribir una expresión regular que reemplace dicha cadena con su patrón repetido más pequeño:

 'xyzzyxxyzzyxxyzzyx' becomes 'xyzzyx', 'abcbaccbaabcbaccbaabcbaccba' becomes 'abcbaccba' 

Usa lo siguiente:

 > re.sub(r'(.+?)\1+', r'\1', 'xyzzyxxyzzyxxyzzyx') 'xyzzyx' > re.sub(r'(.+?)\1+', r'\1', 'abcbaccbaabcbaccbaabcbaccba') 'abcbaccba' > re.sub(r'(.+?)\1+', r'\1', 'iiiiiiiiiiiiiiiiii') 'i' 

Básicamente, coincide con un patrón que se repite (.+?)\1+ , y elimina todo menos el patrón de repetición, que se captura en el primer grupo \1 . También tenga en cuenta que usar un calificador renuente aquí, es decir, +? Hará que el regex regrese bastante.

DEMO .

Como desea que el patrón de repetición más pequeño, algo como lo siguiente debería funcionar para usted:

 re.sub(r'^(.+?)\1+$', r'\1', input_string) 

Los anclajes ^ y $ aseguran que no obtengas coincidencias en medio de la cadena, y al usar .+? en lugar de solo .+ obtendrá el patrón más corto (compare los resultados utilizando una cadena como 'aaaaaaaaaa' ).

Prueba este patrón de expresiones regulares y captura el primer grupo:

 ^(.+?)\1+$ 
  • ^ ancla para comienzo de cuerda / linea
  • . cualquier personaje excepto nuevas líneas
  • + cuantificador para denotar al menos 1 ocurrencia
  • ? hace que el + perezoso en lugar de codicioso, por lo tanto, le dé el patrón más corto
  • () grupo de captura
  • \1+ referencia inversa con el cuantificador para indicar que el patrón debe repetirse al menos una vez
  • $ ancla para final de cadena / linea

Pruébalo aquí: Rubular


La solución anterior hace mucho retroceso que afecta el rendimiento. Si conoce los caracteres que no están permitidos en estas cadenas, entonces puede usar un conjunto de caracteres negado que elimina el retroceso. Por ejemplo, si los espacios en blanco no están permitidos, entonces

 ^([^\s]+)\1+$