re.findall no regresa partido completo?

Tengo un archivo que incluye un montón de cadenas como “tamaño = XXX;”. Estoy probando el módulo re de python por primera vez y estoy un poco desconcertado por el siguiente comportamiento: si uso una canalización para ‘o’ en una expresión regular, solo veo que se devuelve ese bit de coincidencia. P.ej:

>>> myfile = open('testfile.txt','r').read() >>> print re.findall('size=50;',myfile) ['size=50;', 'size=50;', 'size=50;', 'size=50;'] >>> print re.findall('size=51;',myfile) ['size=51;', 'size=51;', 'size=51;'] >>> print re.findall('size=(50|51);',myfile) ['51', '51', '51', '50', '50', '50', '50'] >>> print re.findall(r'size=(50|51);',myfile) ['51', '51', '51', '50', '50', '50', '50'] 

La parte “size =” del partido se ha ido. (Sin embargo, ciertamente se utiliza en la búsqueda, de lo contrario habría más resultados). ¿Qué estoy haciendo mal?

El problema que tiene es que si la expresión regular que re.findall trata de hacer coincidir los grupos de capturas (es decir, las partes de la expresión regular que están entre paréntesis), son los grupos los que se devuelven, en lugar de la cadena coincidente.

Una forma de resolver este problema es usar grupos que no capturan (con el prefijo ?: :).

 >>> import re >>> s = 'size=50;size=51;' >>> re.findall('size=(?:50|51);', s) ['size=50;', 'size=51;'] 

Si la expresión regular que re.findall intenta hacer coincidir no captura nada, devuelve la totalidad de la cadena coincidente.

Aunque el uso de clases de caracteres podría ser la opción más sencilla en este caso particular, los grupos que no capturan proporcionan una solución más general.

Cuando una expresión regular contiene paréntesis, capturan su contenido en grupos, cambiando el comportamiento de findall() para devolver solo esos grupos. Aquí está la sección relevante de los documentos :

(...)

Coincide con cualquier expresión regular dentro de los paréntesis, e indica el inicio y el final de un grupo; el contenido de un grupo se puede recuperar después de que se haya realizado una coincidencia, y se puede hacer coincidir más adelante en la cadena con la secuencia especial \number , que se describe a continuación. Para hacer coincidir los literales '(' o ')' , use \( o \) , o enciérrelos dentro de una clase de caracteres: [(] [)] .

Para evitar este comportamiento, puede usar un grupo que no capture :

 >>> print re.findall(r'size=(?:50|51);',myfile) ['size=51;', 'size=51;', 'size=51;', 'size=50;', 'size=50;', 'size=50;', 'size=50;'] 

De nuevo, desde la documentación:

(?:...)

Una versión que no captura los paréntesis regulares. Coincide con cualquier expresión regular dentro de los paréntesis, pero la subcadena que coincide con el grupo no se puede recuperar después de realizar una coincidencia o hacer referencia más adelante en el patrón.

'size=(50|51);' significa que está buscando size=50 o size=51 pero solo coincide con la parte 50 o 51 (tenga en cuenta los paréntesis), por lo tanto, no devuelve el sign= .

Si desea que se devuelva el sign= , puede hacer:

 re.findall('(size=50|size=51);',myfile) 

Creo que lo que quieres es usar [] en lugar de (). [] que indica el conjunto de caracteres mientras que () indica una coincidencia de grupo. Intenta algo como esto:

 print re.findall('size=5[01];', myfile) 

En algunos casos, el grupo que no captura no es apropiado, por ejemplo, con expresiones regulares que detectan palabras repetidas (ejemplo de documentos de Python )

 r'(\b\w+)\s+\1' 

En esta situación para obtener un partido completo se puede usar

 [groups[0] for groups in re.findall(r'((\b\w+)\s+\2)', text)] 

Tenga en cuenta que \1 ha cambiado a \2 .