2012-09-17 51 views
10

Tengo una cadena que puede tener un patrón de caracteres repetido, p.Regex para eliminar el patrón de caracteres repetidos en una cadena

'xyzzyxxyzzyxxyzzyx' 

Tengo que escribir una expresión regular que reemplazaría tales cadena con su pequeño patrón repetido:

'xyzzyxxyzzyxxyzzyx' becomes 'xyzzyx', 

'abcbaccbaabcbaccbaabcbaccba' becomes 'abcbaccba' 
+0

¿Conoce el patrón o está buscando un patrón repetitivo en una cadena? – Joel

+1

Está buscando el patrón de repetición más pequeño, supongo. – arshajii

Respuesta

5

Usar la 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' 

Es básicamente coincide con un patrón que se repite (.+?)\1+, y elimina todo menos el patrón repetitivo, que se captura en el primer grupo \1. También tenga en cuenta que el uso de un calificador reacio aquí, es decir, +? hará que la expresión regular retroceda bastante.

DEMO.

+0

El problema con esto es que falla en este caso: >>> re.sub (r '(\ w +) \ 1+', r '\ 1', 'iiiiiiiiiiiiiiiiii') produce 'iiiiiiiii' en lugar de 'i' – mercador

+0

@mercador: Veo, hace que el cuantificador '+' sea reacio en lugar de codicioso. He actualizado mi respuesta. –

4

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

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

Los ^ y $ anclas asegurarse de que usted no recibe partidos en el medio de la cadena, y por usando .+? en lugar de solo .+ obtendrá el patrón más corto (compare resultados usando una cadena como 'aaaaaaaaaa').

+1

Y solo tenga en cuenta que esto puede tardar bastante tiempo en fallar si 'input_string' es algo así como' "a" * 1000000 + "b" '. – hobbs

+1

¿Alguna idea de expresiones regulares sin retroceder? El '. +?' Causará un retroceso pesado. – Kash

+0

si lee un libro como 'Programming Perl', puede encontrar una realización de expresiones regulares con ejemplos 'pesados'. Creo que no es una tarea rápida para expresiones regulares. – gaussblurinc

2

Prueba este patrón de expresión y capturar el primer grupo:

^(.+?)\1+$ 
  • ^ ancla para inicio de cadena/línea
  • . cualquier carácter excepto los saltos de línea
  • + cuantificador para denotar al menos 1 ocurrencia
  • ? hace que el + perezoso en lugar de codicioso, por lo tanto, que le da el patrón más corto
  • () grupo de captura
  • \1+ referencia inversa con el cuantificador para denotar esa pauta repita al menos una vez
  • $ ancla para la final de la cadena/línea

prueba aquí: Rubular


La solución anterior hace una gran cantidad de bac ktracking afecta el rendimiento. Si conoce los caracteres que no están permitidos en estas cadenas, 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+$ 
Cuestiones relacionadas