2012-01-26 20 views
5

Estoy intentando analizar algunas cadenas de documentos.regex: cadena con partes opcionales

un ejemplo docstrings es:

Test if a column field is larger than a given value 
    This function can also be called as an operator using the '>' syntax 

    Arguments: 
     - DbColumn self 
     - string or float value: the value to compare to 
      in case of string: lexicographic comparison 
      in case of float: numeric comparison 
    Returns: 
     DbWhere object 

Tanto los Arguments y Returns partes son opcionales. Quiero que mi expresión regular devuelva como grupos la descripción (primeras líneas), la parte Arguments (si está presente) y la parte Returns (si está presente).

La expresión regular que tengo ahora es:

m = re.search('(.*)(Arguments:.*)(Returns:.*)', s, re.DOTALL) 

y trabaja en el caso de las tres partes están presentes pero no tan pronto como Arguments o los Returns partes no están disponibles. He intentado varias variaciones con los modificadores no codiciosos como ??, pero fue en vano.

Editar: Cuando los Arguments y Returns partes están presentes, de hecho me habría sólo me gusta para que coincida con el texto después de Arguments: y Returns: respectivamente.

Gracias!

+1

¿El orden siempre es el correcto? I. e., ¿'Arguments' siempre después del texto estándar y antes de' Returns'? –

+0

Sí, el orden siempre es fijo. – BioGeek

Respuesta

7

Try con:

re.search('^(.*?)(Arguments:.*?)?(Returns:.*)?$', s, re.DOTALL) 

sólo hacer el segundo y tercer grupos opcional añadiendo un ?, y haciendo la fase de clasificación de los dos primeros grupos no expansivo por (de nuevo) añadiendo un ? en ellos (sí, confuso).

Además, si utiliza el modificador no codicioso en el primer grupo del patrón, coincidirá con la subcadena más corta posible, que para .* es la cadena vacía. Puede solucionar esto agregando el carácter de final de línea ($) al final del patrón, lo que obliga al primer grupo a unir la menor cantidad de caracteres posibles para satisfacer el patrón, es decir, toda la cadena cuando no hay Arguments y no Returns secciones, y todo lo anterior a esas secciones, cuando estén presentes.

Editar: bien, si lo que desea es capturar el texto después de los Arguments: y Returns: fichas, que tendrá que meter en un par más grupos. No vamos a utilizar todos los grupos, por lo que nombrarlos -con la <?P<name> notación (otra marca pregunta, argh!) - está empezando a tener sentido:

>>> m = re.search('^(?P<description>.*?)(Arguments:(?P<arguments>.*?))?(Returns:(?P<returns>.*))?$', s, re.DOTALL) 
>>> m.groupdict()['description'] 
"Test if a column field is larger than a given value\n This function can also be called as an operator using the '>' syntax\n\n " 
>>> m.groupdict()['arguments'] 
'\n  - DbColumn self\n  - string or float value: the value to compare to\n   in case of string: lexicographic comparison\n   in case of float: numeric comparison\n ' 
>>> m.groupdict()['returns'] 
'\n  DbWhere object' 
>>> 
+0

¡Funciona como un encanto! ¿Cómo modificaría la expresión regular si, para las partes opcionales, solo quisiera hacer coincidir el texto después de 'Arguments' y' Returns'? – BioGeek

+0

Algo como 're.search ('^ (. *?) (Argumentos: (. *?))? (Devoluciones: (. *))? $', Doc, re.DOTALL)' funciona, pero no lo hago se preocupa por el segundo y cuarto grupo que regresa. – BioGeek

+0

He editado mi respuesta. Solo nombre los grupos y olvídese de 'groups()', use 'groupdict()' en su lugar. – Chewie

3

Si desea hacer coincidir la texto después de las secciones opcionales Arguments: y Returns:, Y no desea usar (?P<name>...) para nombrar sus grupos de captura, también puede usar, (?:...), la versión no capturable de paréntesis regulares.

la expresión regular se vería así:

m = re.search('^(.*?)(?:Arguments:(.*?))?(?:Returns:(.*?))?$', doc, re.DOTALL) 
#      ^^     ^^ 

De acuerdo con la python3 documentation:

(?:...)

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

Cuestiones relacionadas