2010-09-26 27 views
31

Por ejemplo, la expresión regular a continuación hará que la presentación de informes error de aserción de búsqueda hacia atrás no es fijo longitud:¿Cuál es el motivo técnico para "la aseveración de búsqueda DEBE ser de longitud fija" en expresiones regulares?

#(?<!(?:(?:src)|(?:href))=["\']?)((?:https?|ftp)://[^\s\'"<>()]+)#S 

Tal tipo de restricción no existe para lookahead.

+0

¿Qué referencia está usando para “aserción hacia atrás debe fijarse longitud”? – Alex

+0

** la aseveración lookbehind no es de longitud fija ** causará falla, ¿no podemos deducirlo de eso? – wamp

+0

¿Qué motor regex estás usando? Perl? DO#? PHP? Hay muchas herramientas que manejan expresiones regulares, y todas tienen sus propias peculiaridades. – Yuliy

Respuesta

53

Lookahead y búsqueda hacia atrás no son casi tan similar como sus nombres lo indican. La expresión de búsqueda anticipada funciona exactamente igual que si fuera una expresión regular independiente, excepto que está anclada en la posición de coincidencia actual y no consume lo que coincide.

de búsqueda hacia atrás es una historia completamente diferente. Comenzando en la posición de coincidencia actual, retrocede el texto un carácter a la vez, intentando emparejar su expresión en cada posición. En los casos en que no es posible la coincidencia, el lookbehind tiene que recorrer todo el camino hasta el comienzo del texto (un personaje a la vez, recuerda) antes de que se rinda. Compare eso con la expresión de anticipación, que se aplica exactamente una vez.

Ésta es una simplificación excesiva, por supuesto, y no todos los sabores funciona de esa manera, pero se entiende la idea. La forma se aplican lookbehinds es fundamentalmente diferente de (y mucho, mucho menos eficiente que) la forma en que se aplican los símbolos de anticipación. Solo tiene sentido establecer un límite sobre cuánto debe mirar el aspecto detrás.

+4

+1 por la excelente explicación Alan, gracias. :-) –

+0

Entonces, ¿por qué no puedes simplemente mirar primero hacia atrás y luego buscar el resto del patrón? –

+2

@AidanMueller: Algunos sabores (incluido PCRE) admiten el constructo '\ K', que hace precisamente eso:' foo \ Kbar' tiene que coincidir con 'foo' primero, pero pretende que el emparejamiento realmente comenzó en' bar'. Pero eso solo funciona para * positive * lookbehinds. –

8

En primer lugar, esto no es cierto para todas las bibliotecas de expresiones regulares (como .NET).

Para PCRE, la razón parece ser:

La aplicación de búsqueda hacia atrás afirmaciones es decir, para cada alternativa, para mover temporalmente la posición actual hacia atrás por el ancho fijo y luego tratar de igualar .

(al menos, según http://www.autoitscript.com/autoit3/pcrepattern.html).

+1

¿Por qué no utilizar el mismo algoritmo para 'lookahead' y' lookbehind'? ¿No es el prototipo el mismo? – wamp

+2

wamp, entonces tendrías que * revertir * la expresión regular en la mirada hacia atrás y dar un paso atrás. Las expresiones regulares usualmente solo funcionan hacia adelante y revertir una expresión particular es probable que no sea trivial. – Joey

+0

Pudieron implementar un corrector de tamaño de corrección (pruebe '# (? <= Fw (* SKIP) (* FAIL) | f) oo #' mientras que la capacidad de derecha a izquierda es muy escasa. –

2

que tenían el mismo problema y se fija mediante el uso de (?: subexpression)

Define un grupo que no captura. como Write(?:Line)? "WriteLine" en "Console.WriteLine()" "Escribir" en "Console.Write (valor)"

que tenía que cambiar la expresión regular por debajo del cual se supone que debe tomar antes de ,o algo en el inicio de la cadena que me daba aseveración lookbehind no es de longitud fija.

(?<=,|^) 

con esto,

(?:(?<=,)|^) 
2

PCRE no soporta flotante de búsqueda hacia atrás, ya que puede causar graves problemas de rendimiento. Esto se debe a la falta de capacidad de coincidencia de derecha a izquierda: PCRE puede iniciar una bifurcación solo a partir de una izquierda fija, pero a la izquierda de una bifurcación de longitud variable no puede corregirse.

En general, si es posible, intente dividir su parte posterior en patrones de longitud fija. Por ejemplo, en lugar de:

(?<=(src|href)=")etc. 

(1) uso esto:

(?:(?<=src=")|(?<=href="))etc. 

(2) O con \K:

(src|href)="\Ketc. 

Tenga en cuenta que \K no es un verdadero mirar hacia atrás, porque siempre comienza la búsqueda al final del partido anterior (sin posible retroceso en el matc anterior h).

(3) En algunos casos complejos de solo mirar puede buscar con una expresión de búsqueda anticipada "invertida" en una secuencia invertida. No demasiado elegante, pero funciona:

.cte(?="=(ferh|crs)) 
0
grep -P '(?<=((three)|(one)))two' <<< "one two three three two one" 
grep: lookbehind assertion is not fixed length 

grep -P '((?<=(three))|(?<=(one)))two' <<< "one two three three two one" 
one two three three two one 
+2

¡Gracias por tu respuesta! ¿Puede proporcionar algún contexto o información adicional, en lugar de solo los comandos? Eso hará que la respuesta sea más útil para otras personas que buscan información. – roelofs

+1

Esto no proporciona una respuesta a la pregunta. Una vez que tenga suficiente [reputación] (https://stackoverflow.com/help/whats-reputation) podrá [comentar cualquier publicación] (https://stackoverflow.com/help/privileges/comment); en su lugar, [brinde respuestas que no requieran aclaración del autor de la pregunta] (https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can- i-do-instead). - [De la crítica] (/ review/low-quality-posts/18213583) – robinCTS

Cuestiones relacionadas