regular - regex repetitions
Token codicioso templado: ¿qué tiene de diferente colocar el punto antes de la anticipación negativa? (3)
<table((?!</table>).)*</table>
coincide con todas mis etiquetas de tabla, sin embargo,
<table(.(?!</table>))*</table>
no. El segundo parece tener sentido si trato de escribir la expresión en palabras, pero no puedo entender el primero.
¿Alguien puede explicarme la diferencia?
Como referencia, obtuve el término ''Token codicioso templado'' de aquí: http://www.rexegg.com/regex-quantifiers.html#tempered_greed
Dado que Google devuelve esta pregunta SO además de los resultados del
tempered greedy token
, me siento obligado a proporcionar una respuesta más completa.
¿Qué es un token codicioso templado?
La referencia del http://www.rexegg.com/regex-quantifiers.html#tempered_greed rexegg.com es bastante concisa:
En
(?:(?!{END}).)*
, El cuantificador*
aplica a un punto, pero ahora es un punto templado . La anticipación negativa(?!{END})
afirma que lo que sigue a la posición actual no es la cadena{END}
. Por lo tanto, el punto nunca puede coincidir con la llave de apertura de{END}
, lo que garantiza que no saltaremos sobre el delimitador{END}
.
Eso es todo: una ficha codiciosa templada es una especie de clase de caracteres negada para una secuencia de caracteres (cf. clase de caracteres negada para un solo carácter ).
NOTA
: La
diferencia entre un token codicioso templado y una clase de caracteres negados
es que el primero no coincide realmente con el texto que no sea la secuencia en sí, sino con un
solo carácter
que no inicia esa secuencia.
Es decir
(?:(?!abc|xyz).)+
No coincidirá con
def
en
defabc
, pero coincidirá con
def
y
bc
, porque
a
inicia la secuencia de
abc
prohibida, y
bc
no.
Consiste en:
-
(?:...)*
- un grupo cuantificado sin captura (puede ser un grupo de captura, pero no tiene sentido capturar cada carácter individual) (a*
puede ser+
, depende de si una cadena vacía coincide esperado) -
(?!...)
: una anticipación negativa que realmente impone una restricción en el valor a la derecha de la ubicación actual -
.
- (o cualquier carácter (generalmente único)) un patrón de consumo.
Sin embargo, siempre podemos moderar aún más el token mediante el uso de alternancias en la búsqueda anticipada negativa (p. Ej.
(?!{(?:END|START|MID)})
) o reemplazando el punto que coincide con una clase de caracteres negada (p
(?:(?!START|END|MID)[^<>])
Ej.
(?:(?!START|END|MID)[^<>])
al intentar hacer coincidir el texto solo dentro de las etiquetas).
Colocación de parte consumidora
Tenga en cuenta que no se menciona una construcción en la que se coloca una parte consumidora (el punto en la ficha codiciosa templada original)
antes de
la búsqueda anticipada.
La respuesta de Avinash es explicar esa parte claramente:
(.(?!</table>))*
primero coincide con cualquier carácter (pero una nueva línea sin un modificador DOTALL) y luego comprueba si no se sigue con
</table>
resulta en un error para que coincida con
e
en
<table>table</table>
.
La parte consumidora (la
.
) DEBE colocarse después del templado previo
.
¿Cuándo usar token codicioso templado?
Rexegg.com da una idea:
-
Cuando deseamos hacer coincidir un bloque de texto entre el Delimitador 1 y el Delimitador 2 sin ninguna Subcadena 3 en el medio (por ejemplo,
{START}(?:(?!{(?:MID|RESTART)}).)*?{END}
-
Cuando queremos hacer coincidir un bloque de texto que contiene un patrón específico en el interior
sin desbordar
los bloques posteriores (por ejemplo, en lugar de la coincidencia de puntos flojos como en
<table>.*?chair.*?</table>
, usamos algo como<table>(?:(?!chair|</?table>).)*chair(?:(?!<table>).)*</table>
). -
Cuando queremos hacer coincidir la ventana más corta posible entre 2 cadenas.
La coincidencia diferida no ayudará cuando necesite obtener
abc 2 xyz
deabc 1 abc 2 xyz
(consulteabc.*?xyz
yabc(?:(?!abc).)*?xyz
).
Problema de rendimiento
El token codicioso templado consume muchos recursos ya que se realiza una verificación anticipada después de que cada personaje coincida con el patrón de consumo. Desenrollar la técnica de bucle puede aumentar significativamente el rendimiento del token codicioso templado.
Digamos, queremos hacer coincidir
abc 2 xyz
en
abc 1
abc 2 xyz
3 xyz
.
En lugar de verificar cada carácter entre
abc
y
xyz
con
abc(?:(?!abc|xyz).)*xyz
, podemos omitir todos los caracteres que no son
a
o
x
con
[^ax]*
, y luego hacer coincidir todos los que no se siguen con
bc
(con
a(?!bc)
) y todas las
x
que no se siguen con
yz
(con
x(?!yz)
):
abc[^ax]*(?:a(?!bc)[^ax]*|x(?!yz)[^ax]*)*xyz
.
Una ficha codiciosa templada realmente solo significa:
"partido, pero solo hasta cierto punto"
como lo haces:
pones el token que no quieres que coincida como un lookahead negativo
(?!notAllowedToMatch)
delante de un punto.
(coincide con cualquier cosa), luego repite todo con una estrella*
:
((?!notAllowedToMatch).)*
cómo funciona:
"mira y come uno" una y otra vez, moviendo un carácter a la vez de izquierda a derecha a través de la cadena de entrada, hasta que se vea la secuencia no permitida (o el final de la cadena), momento en el que se detiene la coincidencia.
La respuesta más detallada de Wiktor es agradable, solo pensé que era necesaria una explicación más simple.
((?!</table>).)*
comprobaría que ese carácter en particular que va a coincidir no debe ser un carácter inicial en la cadena
</table>
.
En caso afirmativo, solo coincide con ese personaje en particular.
*
repite el mismo cero o más veces.
(.(?!</table>))*
coincide con cualquier carácter solo si no es seguido por
</table>
, cero o más veces.
Por lo tanto, esto coincidiría con todos los caracteres dentro de la etiqueta de la tabla para eliminar el último carácter, ya que el último carácter es seguido por
</table>
.
Y el siguiente patrón
</table>
afirma que debe haber una etiqueta de tabla de cierre al final del partido.
Esto hace que el partido falle.
Ver here