2009-04-11 19 views
8

He tenido problemas en Regexes para dividir un código en componentes funcionales. Pueden romperse o les puede tomar mucho tiempo terminar. La experiencia plantea una pregunta:¿Cuándo debería usar un analizador?

"¿Cuándo debería usar un analizador?"

+0

No estoy seguro si es un duplicado, pero consulte las siguientes publicaciones: * [¿Cuándo es un problema demasiado complejo para una expresión regular?] (Http: // stackoverflow.com/questions/230517/when-is-a-problem-too-complex-for-a-regular-expression) * [Alternativas a expresiones regulares] (http://stackoverflow.com/questions/514313/alternatives-to -regular-expressions) – dirkgently

Respuesta

9

Debe utilizar un analizador cuando usted está interesado en el significado léxico o semántico del texto, cuando los patrones pueden variar. Los analizadores son generalmente exagerados cuando simplemente busca coincide o reemplaza patrones de caracteres, independientemente de su significado funcional.

En su caso, parece estar interesado en el significado detrás del texto ("componentes funcionales" del código), por lo que un analizador sería la mejor opción. Sin embargo, Parsers puede hacer uso interno de la expresión regular, por lo que no deben considerarse mutuamente excluyentes.


Un "analizador" no significa automáticamente que deba ser complicado, sin embargo. Por ejemplo, si está interesado en bloques de código C, simplemente podría analizar grupos anidados de {y}. Este analizador solo estaría interesado en dos tokens ('{' y '}') y los bloques de texto entre ellos.

Sin embargo, una comparación simple de expresiones regulares no es suficiente debido a la semántica anidada. Tome el siguiente código:

void Foo(bool Bar) 
{ 
    if(Bar) 
    { 
     f(); 
    } 
    else 
    { 
     g(); 
    } 
} 

Un analizador va a entender el alcance global de Foo, así como cada ámbito interno contenido dentro de Foo (los if y else bloques). Cuando encuentra cada '{' token, "entiende" su significado. Una búsqueda simple, sin embargo no entiende el significado detrás del texto y puede interpretar el siguiente para ser un bloque, que, por supuesto, sabemos que no es correcta:

{ 
    if(Bar) 
    { 
     f(); 
    } 
0

Su pregunta es un poco vago, pero supongo que mi La opinión es que cuando su expresión regular se vuelve complicada o toma demasiado tiempo, y usted tiene un "lenguaje" razonablemente definido para manejar, un analizador será más fácil.

No creo que pueda establecer una línea en la arena y decir que cualquier cosa en un lado se puede hacer con expresiones regulares, y en el otro lado necesita un analizador. Depende de la situación.

1

Tiene que usar un analizador tan pronto como tenga un problema, las expresiones regulares no están destinadas (o simplemente no pueden) resolver. Coincidencia (no) paréntesis equilibrado (recursivamente), por ejemplo, es uno de esos problemas. A pesar de que algunos sabores, como PCRE, te llevan muy lejos, no convencen a un analizador escrito a mano.

2

Hay algunos casos de uso convincentes para analizadores sobre expresiones regulares. Debe utilizar un analizador en lugar de una expresión regular:

  • Siempre que los tipos de expresiones que le gustaría trabajar con son más complejos que algunas entidades semánticas (etiquetas, variables, números de teléfono, etc.).
  • Siempre que necesite conocer el significado semántico del texto en lugar de simplemente hacer coincidir un patrón. Por ejemplo, si intenta hacer coincidir todas las formas posibles de escribir un número de teléfono, es probable que un analizador sea mejor que una expresión regular. Si intenta hacer coincidir un patrón específico que coincida con un número de teléfono, una expresión regular probablemente esté bien.
  • Siempre que no se pueda garantizar que la entrada esté bien formada.
  • Si está trabajando completamente dentro de la estructura de un lenguaje bien definido que tiene una especificación de sintaxis (C#, XML, C++, Ruby, etc.), ya habrá un analizador sintáctico, por lo que tendrá que trabajar un poco para ti.
+0

+1 para los ejemplos concretos. –

+0

@John Feminella, podría estar equivocado, pero no estoy seguro de estar de acuerdo con el ejemplo del número de teléfono. Si queremos hacer coincidir varias formas de escribir un número de teléfono, creo que todavía puede estar muy bien representado como una expresión regular (con una lista opcional de patrones). Este puede no ser un muy buen ejemplo de un caso cuando se necesita semántica. – Parag

+0

@Parag: Desearía tener la feliz paz interior que proviene de creer que los números de teléfono se pueden combinar con expresiones regulares. Los números de teléfono son tremendamente complicados para validar por completo. –

1

Aquí hay algunos casos de uso, cortesía de Steve Yegge: Rich Programmer Food.

+0

+1 para la publicación de blog personal. Compré tres libros sobre compiladores, recurrencia y cosas relacionadas después de leer =) –

+0

Gracias. En ese caso, échele un vistazo a: http://stackoverflow.com/questions/725372/which-programming-languages-text –

3

se necesita un analizador cuando:

  1. lenguaje no es regular (wikipedia)
  2. necesita un árbol de análisis (más generalmente cuando se necesita para ejecutar acciones contextualmente)
  3. cuando la expresión regular resultante es demasiado oscuro/complejo

Mi 2 centavos.

+0

No me refiero a nitpick, pero para el punto 1, ¿necesitamos un lexer o un analizador – Parag

2

The Dragon Book tiene una pequeña sección sobre lo que no se puede utilizar expresiones regulares para:

  • no pueden detectar la repetición de una cadena, lo que significa que no puede coincidir con construcciones como 'WCW', donde w es la misma sucesión de símbolos
  • Solo puede detectar un número fijo de repeticiones o un número no especificado de repeticiones, lo que quiere decir que no puede usar un token ya analizado para determinar el número de repeticiones, algo como: 'n s1 s2 ... sn '
  • "Las expresiones regulares no se pueden usar para describir construcciones equilibradas o anidadas, [ como] el conjunto de cadenas de todos los paréntesis equilibrados"

Para 1 y 2, hay una explicación simple, no se puede captura una subcadena para que pueda coincidir más tarde. Si lo hicieras, entonces estarías usando un analizador sintáctico. Solo piense en cómo usaría expresiones regulares para esos casos, e intuitivamente llegará a la conclusión de que no puede. :)

Para 3, es lo mismo que el problema en K & R para analizar literales de cadena. No se puede simplemente decir una cadena literal entre el primer '' '' y el segundo '' '', pero ¿qué sucede cuando hay una cita escapada (\ ")?

En cuanto a la relación con la paradoja de Russel, creo su corazonada es correcta, porque el problema es la limitada capacidad de introspección de Regex. El libro tiene referencias a las pruebas. Si quiere, puedo buscarlas.

+0

¿Cuáles son las premisas para cada argumento? 1. no hay inferencia sobre sí mismo 2. dado que la memoria es limitada, los tokens deben ser finitos 3. todos - No sé por qué, pero cuando leí la escritura empecé a pensar en la paradoja de Russell. ¿Puedes reducir sus pruebas? –

+0

He actualizado mi respuesta. –

+0

@Asdrei Vajna II Por favor, intente con "% s @ \\ (h \\ (el \\) lo \\) @ la cadena es \ 1 y la subcadena es \ 2 @", cuando solo tiene un línea con una palabra "hola". –

0

Hay cosas que la expresión regular no puede hacer mientras el analizador puede hacer
Por ejemplo:.

Inicio :: = (interior);
interior :: = Inicio | x;

La expresión regular no podría hacer eso porque regex no puede seguir si hay el mismo número de paréntesis de abrir y cerrar. Es por eso que cuando intentas tokenar y analizar un archivo grande, se espera que el analizador sea utilizado, mientras que Regex simplemente puede encontrar patrones especiales dentro del archivo.

Cuestiones relacionadas