2012-05-02 8 views
8

He leído todas las publicaciones relacionadas y he rastreado Internet, pero esto realmente me está golpeando.¿Cómo hago que el aspecto negativo de Python sea menos codicioso?

Tengo un texto que contiene una fecha.
Me gustaría capturar la fecha, pero no si está precedida por una cierta frase.

Una solución directa es agregar un aspecto negativo detrás de mi RegEx.

Aquí hay algunos ejemplos (usando findall).
Solo quiero capturar la fecha si no está precedida por la frase "a partir de".

19-2-11
algo algo 15-4-11
tal y como de 29-5-11

Aquí está mi expresión regular:

(?<!as of)(\d{1,2}-\d{1,2}-\d{2}) 

Resultados esperados:

['19 -2-11 ']
['15 -4-11']
[]

Los resultados reales:

['19 -2-11' ]
['15 -4-11 ']
[' 9/5/11' ]

en cuenta que es 9 no 29. Si cambio \d{1,2} a algo sólido como \d{2} en el primer patrón :

bad regex for testing: (?<!as of)(\d{2}-\d{1,2}-\d{2}) 

Luego recibo los resultados esperados. Por supuesto, esto no es bueno porque me gustaría combinar días de 2 dígitos y días de un solo dígito.

Aparentemente mi mirada negativa detrás es quity codiciosa - más que mi captura de fecha, por lo que está robando un dígito de ella y está fallando. Intenté todos los medios para corregir la avaricia que se me ocurre, pero no sé cómo arreglar esto.

Me gustaría que mi captura de fecha coincida con la mayor codicia, y luego se aplicará mi mirada negativa detrás. es posible? Mi problema parecía ser un buen uso de imágenes negativas y no demasiado complicado. Estoy seguro de que podría lograrlo de otra manera si es necesario, pero me gustaría aprender cómo hacerlo.

¿Cómo hago que el aspecto negativo de Python sea menos codicioso?

Respuesta

1

La razón se debe a que no es codicioso de búsqueda hacia atrás. Esto sucede porque el motor regex intenta hacer coincidir el patrón en cada posición que puede.

Avanza mediante la frase such and such as of 29-5-11 que coincide exitosamente con (?<!as of) al principio, pero al no coincidir con \d{1,2}.

Pero luego el motor se encuentra en la posición such and such as of !29-5-11 (marcado con !). Pero aquí no coincide con (?<!as of).

Y avanza a la siguiente posición: such and such as of 2!9-5-11. Donde coincide con éxito (?<!as of) y luego \d{1,2}.

¿Cómo evitarlo?

La solución general es formular el patrón lo más claro posible.

En este caso yo prefijo el dígito con el espacio necesario o el comienzo de la cadena.

(?<!as of)(?:^|\s+)(\d{1,2}-\d{1,2}-\d{2}) 

La solución de Mark Byers también es muy buena.

Creo que es muy importante entender la razón por la cual el motor regex se comporta de esta manera y da resultados no deseados.

Por cierto, la solución que proporcioné arriba no funciona si hay 2 o más espacios. No funciona porque la primera posición coincide aquí such and such as of ! 29-5-11 con el patrón mencionado anteriormente.

¿Qué se puede hacer para evitarlo?

Desafortunadamente lookbehind en el motor de expresiones regulares de Python no admite los cuantificadores + o *.

creo que la solución más sencilla sería la de asegurarse de que no hay espacios antes (?:^|\s+) (meaing que todos los espacios son consumidos por (?:^|\s+) inmediatamente después de cualquier texto no-espacio (y en caso de que el texto es as of, terminan avanzar y retroceder a la siguiente posición inicial de iniciar la búsqueda de nuevo en la siguiente posición del texto buscado).

re.search(r'(?<!as of)(?<!\s)(?:^|\s+)(\d{1,2}-\d{1,2}-\d{2})','such and such as of 29-5-11').group(1) 
+0

Esto es fantástico, encuentro '(?:^| \ S +)' y su explicación es muy clara. Siento que mi pregunta es respondida.:) Puramente por el conocimiento y no por la necesidad, me gustaría aprender a modificar esto para que el '\ s' sea opcional, de modo que' algo algo15-4-11' coincida, pero puedo ser capaz de entenderlo yo mismo. ¡Gracias! –

+0

@ChristopherGalpin Creo que se puede lograr muy fácilmente usando '*' (de 0 a infinito) en lugar de '+' (de 1 a infinito) en esta parte del patrón: '(?:^| \ S +) ' – ovgolovin

+0

Tenía la esperanza de que fuera tan fácil, pero evidentemente no, rompe el emparejamiento' de 'de la misma manera que la pregunta original. –

7

Esto no tiene nada que ver con la codicia. La codicia no cambia si una expresión regular concuerda o no: cambia solo el orden en que se realiza la búsqueda. El problema aquí es que su expresión regular debe ser más específica para evitar coincidencias no deseadas.

Para solucionarlo se podría requerir un límite de palabra justo antes de su partido:

(?<!as of)\b(\d{1,2}-\d{1,2}-\d{2}) 
#   ^^ add this 
+0

Bueno, funcionó y ahora me siento tonto :) Gracias tu! Sé que esto amplía la pregunta original, pero ¿hay alguna manera sencilla de engullir espacios en blanco entre la frase y la fecha? El aspecto detrás debe ser de ancho fijo para que no pueda entrar ahí, pero agregar \ s * cerca de la fecha parece resucitar el problema. –

+2

¿Qué tal esto: '(?

+0

Gracias, estoy encontrando esto muy educativo. –

-1

Una solución sencilla sería la de tirar todas las líneas que coincidan 'como de' antes de usar la expresión regular para aislar las fechas

+2

"Fred era el jefe desde ayer. En el poder desde el 31-12-11, ..." => FAIL –

Cuestiones relacionadas