Bien, veamos qué está pasando aquí. Usted afortunadamente ya ha simplificado el problema a lo que sucede cuando se aplica la expresión regular
(d+)*@
a la cadena
ddddd
que claramente no puede ser igualada porque el @
falta. Pero, ¿qué impide que el motor regex lo descubra rápidamente?
Bueno, (d+)*
, en esencia, se puede cumplir con los siguientes resultados (cada grupo separados por espacios):
ddddd
dddd d
ddd dd
dd ddd
d dddd
ddd d d
dd d dd
d d ddd
dd dd d
d dd dd
d ddd d
d d d dd
d d dd d
d dd d d
dd d d d
d d d d d
Así que hay una manera de hacer coincidir la cadena, sin romper la cadena, cuatro maneras de romper se divide en dos cuerdas, seis maneras de dividirlo en tres, cuatro para dividirlo en cuatro, y uno para dividirlo en cinco cuerdas. Todas estas combinaciones deben ser verificadas por el motor de expresiones regulares antes de que pueda declarar la falla de coincidencia cuando finalmente tenga que enfrentar el siguiente @
.
¿Por qué no se da cuenta de eso antes? Bueno, algunos motores de expresiones regulares pueden hacerlo con un ejemplo simplificado. Apuesto a que Larry Wall tiene eso cubierto. Pero tu expresión regular real es un poco más compleja, así que supongo que sería mucho más difícil averiguarlo de antemano. Además, hay una manera simple de garantizar toda esta combinación: el intento no ocurre. Pero volveré a eso más tarde.
me había estado preguntando cómo muchas de estas combinaciones no serían para una cadena más larga que aquellos insignificantes cinco d
s:
Tomemos una cadena de longitud m
(que se puede cortar aparte en m-1
posiciones diferentes). Digamos n = m-1
.A continuación, se puede calcular el número de combinaciones de la siguiente manera:
1 + (n!/(1! * (n-1)!)) + (n!/(2! * (n-2)!)) + ... + (n!/(n! * (n-n)!))
Los primeros y últimos artículos son siempre 1, pero los elementos en el medio puede llegar a ser muy grande. Vamos a escribir un pequeño programa de Python:
>>> from math import factorial as f
>>> def comb(n,x):
... return f(n) // (f(x) * f(n-x))
...
>>> def ways_to_split(len):
... return 1 + sum(comb(len-1,x) for x in range(1,len))
...
>>> ways_to_split(5)
16
OK, parece que funciona. Vamos a intentar algo más grande:
>>> ways_to_split(10)
512
>>> ways_to_split(40)
549755813888
>>> ways_to_split(100)
633825300114114700748351602688
Oye, hay un patrón aquí: ways_to_split(n)
es igual a 2**(n-1)
. Ver Mathematics SE para una prueba. De todas formas. Su expresión regular tiene O(2^n)
complejidad. Bueno, ahora ves por qué eso podría llevar un tiempo ...
Afortunadamente, muchos motores regex ofrecen protección contra esto: cuantificadores posesivos o grupos de captura atómica.
(d++)*
o
(?>d+)*
tanto asegurarse de que lo ha emparejado d+
no será cedido otra vez por intentar otras combinaciones. Buenas noticias, ¿verdad?
Bueno, no si utiliza JavaScript. No es compatible con ninguna de esas características.
Por lo tanto, sea necesario volver a escribir su expresión regular no ser susceptibles a dar marcha atrás como esto:
En lugar de
(([_\.\-]?[a-zA-Z0-9]+)*)
uso
[a-zA-Z0-9]+([_.-][a-zA-Z0-9]+)*
O deja de tratar de utilizar una expresión regular para validar una dirección de correo electrónico que no funciona confiablemente, nunca, de todos modos.
curiosamente esto está bien en Firefox pero también se bloquea IE 9 –
En Firefox completa incluso con una cadena 'ddddddd ...' de longitud 4096. – cherouvim
Para el registro, pude reducirlo a '/ [ad ] ([ad] +) + A/.test ('dddddddddddddddddddddddddddddd'); ', que también se cuelga; espero que ayude a encontrar el problema. – pimvdb