Esta es una gran expresión regular para las fechas ... Sin embargo, se cuelga indefinidamente en esta página que intenté ... Quería probar esta página (http://pleac.sourceforge.net/pleac_python/datesandtimes.html) por el hecho de que tiene muchas fechas y quiero obtenerlas todas. No entiendo por qué está colgando cuando no lo hace en otras páginas ... ¿Por qué está colgando mi expresión regular y / o cómo podría limpiarlo para que sea mejor / eficiente?

Código Python:

monthnames = "(?:Jan\w*|Feb\w*|Mar\w*|Apr\w*|May|Jun\w?|Jul\w?|Aug\w*|Sep\w*|Oct\w*|Nov(?:ember)?|Dec\w*)"

pattern1 = re.compile(r"(\d{1,4}[\/\\\-]+\d{1,2}[\/\\\-]+\d{2,4})")

pattern4 = re.compile(r"(?:[\d]*[\,\.\ \-]+)*%s(?:[\,\.\ \-]+[\d]+[stndrh]*)+[:\d]*[\ ]?(PM)?(AM)?([\ \-\+\d]{4,7}|[UTCESTGMT\ ]{2,4})*"%monthnames, re.I)

patterns = [pattern4, pattern1]

for pattern in patterns:
    print re.findall(pattern, s)

Por cierto ... cuando digo que lo estoy intentando contra este sitio ... lo estoy intentando contra la fuente de la página web.

4
user233864 18 dic. 2009 a las 22:11

4 respuestas

La mejor respuesta

Debe leer Dominar expresiones regulares. El problema es:

(?:[\d]*[\,\.\ \-]+)*

Que lleva tiempo exponencial. Intenta usar:

(?:[\d,. \-]*[,. \-])?

Que debe coincidir con las mismas cosas pero tomar tiempo lineal. Después de comprobar su ejemplo, esto sí acelera las cosas.

También parece haber introducido accidentalmente grupos de captura en su patrón en algún momento: cambiar p. (AM) a (?: AM) para arreglar eso. Esto nos da el siguiente resultado de su ejemplo anterior:

[' Aug  6 20:43:20 2003', ' Mar 14 06:02:55 1973', ' March 14 06:02:55 AM 1973', ' Jun 16 20:18:03 1981']
['2003-08-06', '2003-08-07', '2003-07-23', '1973-01-18', '3/14/1973', '16/6/1981', '16/6/1981', '16/6/1981', '16/6/1981', '08/08/2003']

Para entrar en detalles (que el libro al que me refiero es muy bueno), * y + funcionan (en NFA como python re) en lugar de un bucle. El bucle interno del patrón original coincidirá con una larga cadena de dígitos, pero cuando el patrón posterior no coincida, "los abandonará" uno a la vez. El bucle externo volverá a ejecutar el bucle interno en el patrón restante y, por supuesto, inmediatamente tomará los dígitos nuevamente. Cada vez que una instancia del bucle interno abandona un dígito, se convocará una nueva copia para recuperarlo. Eventualmente, una vez que el motor haya pasado por todas las formas posibles de dividir esa cadena de dígitos (un número exponencial de posibilidades), moverá el punto de partida hacia adelante un carácter ... e intenta nuevamente.

En otra nota, su patrón se ve un poco loco;)

5
Alice Purcell 16 oct. 2014 a las 11:25

Primero, debe leer sobre lo que significa una cadena r"": solo tiene que poner barras invertidas donde realmente quiere barras diagonales inversas, por lo que su expresión regular debería ser:

monthnames = "(?:Jan\w*|Feb\w*|Mar\w*|Apr\w*|May|Jun\w?|Jul\w?|Aug\w*|Sep\w*|Oct\w*|Nov(?:ember)?|Dec\w*)"

pattern1 = re.compile(r"(\d{1,4}[-/]+\d{1,2}[-/]+\d{2,4})")

pattern4 = re.compile(r"(?:\d*[,. -]+)*%s(?:[,. -]+\d+[stndrh]*)+[:\d]*[ ]?(PM)?(AM)?([ -+\d]{4,7}|[UTCESTGMT ]{2,4})*"%monthnames, re.I)

En cuanto a su problema real, Python no funciona bien con un * anidado dentro de un *. Cambie pattern4 a esto (el primer \d* se convierte en \d+):

pattern4 = re.compile(r"(?:\d+[,. -]+)*%s(?:[,. -]+\d+[stndrh]*)+[:\d]*[ ]?(PM)?(AM)?([ -+\d]{4,7}|[UTCESTGMT ]{2,4})*"%monthnames, re.I)

Y la expresión regular regresa rápidamente, imprimiendo esto:

[('', '', '2003'), ('', '', '1973'), ('', 'AM', ' 1973'), ('', '', '1981"')]
['2003-08-06', '2003-08-07', '2003-07-23', '1973-01-18', '3/14/1973', '16/6/1981', '16/6/1981', '16/6/1981', '16/6/1981'
, '08/08/2003']

Aunque no sé si eso es lo que querías.

0
Ned Batchelder 18 dic. 2009 a las 19:46

La forma en que se escribe la expresión regular provocará un lote de retroceso. Además del consejo sobre cómo ejecutarlo en fragmentos de texto más pequeños, también puede tener una expresión regular más simple (y por lo tanto más rápida) que filtre el texto que no puede coincidir.

0
Alex Brasetvik 18 dic. 2009 a las 19:43

El evaluador de expresiones regulares de Python puede llevar mucho tiempo. Desafortunadamente, se ejecuta en el peor de los casos exponencial.

Supongo que su "s" contiene una copia de toda la página. Si es así, eso podría causar retrocesos muy largos en el evaluador de expresiones regulares. Tal vez debería dividir la página en trozos más pequeños y ejecutarlos individualmente a través de su expresión regular. Puede usar un analizador HTML como beautifulsoup y ejecutar la expresión regular en cada nodo de texto individualmente. Esto podría reducir el tiempo de ejecución.

0
McPherrinM 18 dic. 2009 a las 19:22