2010-06-04 10 views
6

Tengo un bloque de texto posiblemente grande para buscar instancias de [[...]], donde el ... puede ser cualquier cosa, incluidos otros corchetes (aunque no se pueden anidar; la primera instancia de ]] después de ]] finaliza la coincidencia).¿Es mejor usar un calificador no codicioso o un lookahead?

puedo pensar en dos formas para que coincida con este texto:

  • El uso de un calificativo no expansivo: /\[\[.+?\]\]/
  • Usando una búsqueda hacia delante: /\[\[(?:(?!\]\]).)+\]\]/

Es una opción intrínsecamente mejor que el otro, desde el punto de vista del rendimiento (yo diría que el primero es probablemente más legible)? Recuerdo haber leído que es mejor no usar calificadores no codiciosos, pero no puedo encontrar una fuente para eso ahora.

Respuesta

6

En este caso, es mejor utilizar un cuantificador no codicioso.

Tome esta cadena ejemplo "[[a]b]]"

no expansivo cuantificador

 
     \[\[.+?\]\] 
Atom # 1 2 3 4 5 
  1. Atom # 1 \[ partidos
  2. Atom # 2 \[ partidos
  3. Atom # 3 .+? coincide con el "a"
  4. Atom # 4 \] partidos
  5. Atom # 5 \] falla, de nuevo a # 3, pero mantener posición de la cadena
  6. Atom # 3 .+? coincide con la posición de la cadena "]"
  7. Atom # 4 \] falla, de nuevo a # 3, pero mantener
  8. Atom # 3 .+? coincide con los "b"
  9. Atom # 4 \] coincidencias
  10. Atom # 5 \] partidos
  11. éxito

lookahead:

 
     \[\[(?:(?!\]\]).)+\]\] 
Atom # 1 2 3 4  5 6 7 
  1. Atom # 1 \[ partidos
  2. Atom # 2 \[ partidos
  3. Atom # 4 (?!\]\]) tiene éxito (es decir,no partido) inmediatamente en "a", vaya en
  4. Atom # 5 . coincide con el "a", repita en el # 3
  5. Atom # 4 (?!\]\]) logra coincidencia parcial en "]"
  6. Atom # 4 (?!\]\]) tiene éxito (es decir, no partido) en "b", vaya en
  7. Atom # 5 . coincide con el "]", repita en el # 3
  8. Atom # 4 (?!\]\]) tiene éxito (es decir, no partido) inmediatamente en "b", ir en
  9. Atom # 5 . coincide con el "b", repetir en el # 3
  10. Atom # 4 (?!\]\]) logra coincidencia parcial en "]"
  11. Atom # 4 (?!\]\]) logra completo partido en "]", ergo: # 4 falla, la salida # 3
  12. Atom # 6 \] partidos
  13. Atom # 7 \] los partidos
  14. éxito

Parece que el cuantificador no codicioso tiene menos trabajo por hacer.

Descargo de responsabilidad: Este es un ejemplo artificial y el rendimiento en la vida real puede diferir, dependiendo de la entrada, la expresión real y la implementación del motor de expresiones regulares. Solo estoy 98% seguro de que lo que describí aquí es lo que realmente está sucediendo, entonces estoy abierto a las correcciones. Además, como con todos los consejos de rendimiento, no tome esto al pie de la letra, haga sus propias comparaciones de referencia si quiere saber con certeza.

0

Creo que es mejor usar el calificador no codicioso. ¿Estás seguro de que el artículo que leíste no decía "ten cuidado con codicioso que coincida?"

+1

Tal vez la advertencia se debió a que la concordancia no codiciosa puede causar un gran retraso. –

+0

Sí. El contexto era diferente, era un argumento para usar una clase de caracteres negada específica en lugar de '. *?' –

3

Otra variante: /\[\[((?:\]?[^]])+)]]/

Utiliza ni los cuantificadores no codiciosos ni mirar-aheads. Permite un solo ] antes de cualquier no ]. Si hubiera dos ] en secuencia, la repetición interna se detendría, y el emparejamiento finalizaría.

Este patrón sería el mejor para usar con los motores regex compiladores de FSA. En los motores de seguimiento, podría ser más lento que la variante no codiciosa.

+0

Este también es probablemente el patrón que más se aproxima a la idea del problema. –

1

¿Qué sabor regex estás usando? Si se trata de uno que es compatible con los cuantificadores posesivos, hay una alternativa mucho mejor:

\[\[(?:[^\]]++|\](?!\]))*+\]\] 

[^\]]++ engulle caracteres que no sean ] y no molesta a guardar la información de estado que haría que dar marcha atrás posible. Si aparece un ], realiza un análisis anticipado para ver si hay otro. Envolviendo todo en otro cuantificador posesivo significa que solo mira hacia adelante cada vez que ve un ], y solo retrocede una vez: cuando encuentra el ]] de cierre.

Los cuantificadores posesivos son compatibles con los sabores Java, JGSoft, PCRE (PHP), Oniguruma (Ruby 1.9) y Perl 5.12.Todos esos sabores también apoyan grupos atómicos, los cuales pueden ser utilizados para lograr el mismo efecto:

\[\[(?>(?:(?>[^\]]+)|\](?!\]))*)\]\] 

El sabor .NET soporta grupos atómicos, pero no cuantificadores posesivos.

Cuestiones relacionadas