Token codicioso moderado: ¿qué tiene de diferente colocar el punto antes de la mirada negativa?

<table((?!).)* 

coincide con todas mis tags de tabla, sin embargo,

 <table(.(?!))* 

no. El segundo parece tener sentido si trato de escribir la expresión en palabras, pero no puedo darle sentido al primero.

¿Alguien me puede explicar la diferencia?

Como referencia, obtuve el término ‘Token codicioso templado’ desde aquí: http://www.rexegg.com/regex-quantifiers.html#tempered_greed

Dado que Google devuelve esta pregunta SO sobre los resultados para el tempered greedy token , me siento obligado a proporcionar una respuesta más completa.

¿Qué es un Token Greedy Templado?

La referencia token codiciosa rexegg.com es bastante conciso:

En (?:(?!{END}).)* , El * cuantificador se aplica a un punto, pero ahora es un punto atenuado . El lookahead negativo (?!{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: una ficha codiciosa atemperada es una especie de clase de carácter negada para una secuencia de caracteres (véase la clase de carácter negada para un solo personaje ).

NOTA : La diferencia entre un token codicioso moderado y una clase de carácter negada 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 abc prohibida, y bc no lo hace.

Consiste en:

  • (?:...)* – un grupo cuantificado que no captura (puede ser un grupo de captura, pero no tiene sentido capturar cada carácter individual) (a * puede ser + , depende de si una coincidencia de cadena vacía es esperado)
  • (?!...) – una anticipación negativa que en realidad 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 atemperar más el token utilizando alternancias en la búsqueda anticipada negativa (por ejemplo, (?!{(?:END|START|MID)}) ) o reemplazando el punto que todo coincide con una clase de carácter negada (por ej (?:(?!START|END|MID)[^<>]) cuando intenta hacer coincidir texto solo dentro de las tags).

Consumir la colocación de la pieza

Tenga en cuenta que no se menciona una construcción en la que una parte consumidora (el punto en el token avaro templado original) se coloca antes de la anticipación. La respuesta de Avinash explica claramente esa parte: (.(?!))* primero coincide con cualquier carácter (pero una nueva línea sin un modificador DOTALL) y luego verifica si no se sigue con da como resultado una falla para que coincida con e en la

table

. La parte consumidora (la . ) DEBE colocarse después del revenido .

¿Cuándo usar token codicioso moderado?

Rexegg.com da una idea:

  • Cuando queremos hacer coincidir un bloque de texto entre Delimitador 1 y Delimitador 2 sin Subesquema 3 en el medio (por ejemplo, {START}(?:(?!{(?:MID|RESTART)}).)*?{END}
  • Cuando queremos unir un bloque de texto que contiene un patrón específico dentro sin desbordar los bloques subsiguientes (por ejemplo, en lugar de la coincidencia de puntos perezosos como en
    .*?chair.*?

    , usaríamos algo como

    (?:(?!chair|).)*chair(?:(?!
    ).)*

    ).

  • Cuando queremos hacer coincidir la ventana más corta posible entre 2 cadenas. La coincidencia diferida no será de ayuda cuando necesite obtener abc 2 xyz de abc 1 abc 2 xyz (consulte abc.*?xyz y abc(?:(?!abc).)*?xyz ).

Problema de rendimiento

El token codicioso moderado consume muchos recursos ya que se realiza una comprobación anticipada después de que cada carácter coincide con el patrón de consumo. Desenrollar la técnica de bucle puede boost significativamente el rendimiento del token codicioso templado.

Digamos, queremos 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 unir 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 .

((?!).)* comprobaciones para que el personaje en particular vaya a coincidir no deben ser un carácter inicial en la cadena . Si es así, entonces solo coincide con ese personaje en particular. * repite el mismo cero o más veces.

(.(?!))* coincide con cualquier carácter solo si no va seguido de , cero o más veces. Por lo tanto, esto coincidiría con todos los caracteres dentro de la etiqueta de tabla excepto el último carácter, ya que el último carácter es seguido por . Y el siguiente patrón afirma que debe haber una etiqueta de cierre de mesa al final de la coincidencia. Esto hace que la coincidencia falle.

Mira aquí

Una ficha codiciosa atemperada realmente solo significa:

“coincidir, pero solo hasta cierto punto”

como lo haces:

pones la ficha que no quieres que coincida con un lookahead negativo (?!notAllowedToMatch) delante de un punto . (coincide con una cosa), luego repites todo eso con una estrella * :

((?!notAllowedToMatch).)*

cómo funciona:

“mira, y come uno” una y otra vez, moviendo un carácter de vez en cuando de izquierda a derecha a través de la cadena de entrada, hasta que se vea la secuencia prohibida (o el final de la cadena), en cuyo punto se detiene el partido.

La respuesta más detallada de Wiktor es agradable, solo pensé que una explicación más simple estaba en orden.