Estoy tratando de encontrar una mejor solución para hacer un analizador sintáctico de algunos de los formatos de archivo famosos, como: EDIFACT y TRADACOMS .
Si no está familiarizado con estos estándares, consulte este ejemplo de Wikipedia:
Consulte a continuación un ejemplo de un mensaje EDIFACT utilizado para responder a una solicitud de disponibilidad del producto:
UNA:+.? '
UNB+IATB:1+6XPPC+LHPPC+940101:0950+1'
UNH+1+PAORES:93:1:IA'
MSG+1:45'
IFT+3+XYZCOMPANY AVAILABILITY'
ERC+A7V:1:AMD'
IFT+3+NO MORE FLIGHTS'
ODI'
TVL+240493:1000::1220+FRA+JFK+DL+400+C'
PDI++C:3+Y::3+F::1'
APD+714C:0:::6++++++6X'
TVL+240493:1740::2030+JFK+MIA+DL+081+C'
PDI++C:4'
APD+EM2:0:130::6+++++++DA'
UNT+13+1'
UNZ+1+1'
El segmento UNA es opcional. Si está presente, especifica los caracteres especiales que se utilizarán para interpretar el resto del mensaje. Hay seis caracteres que siguen a UNA en este orden:
- separador de elementos de datos de componentes (: en esta muestra)
- separador de elementos de datos (+ en esta muestra)
- notificación decimal (. en esta muestra)
- liberar personaje (? en esta muestra)
- reservado, debe ser un espacio
- terminador de segmento ('en esta muestra)
Como puede ver, solo se trata de algunos datos formateados de una manera especial que esperan ser analizados (al igual que los archivos XML ).
Ahora mi sistema está construido en PHP y pude crear un analizador utilizando expresiones regulares para cada segmento, pero el problema no es que todos implementen el estándar a la perfección.
Algunos proveedores tienden a ignorar por completo los segmentos y campos opcionales. Otros pueden optar por enviar más datos que otros. Es por eso que me vi obligado a crear validadores para segmentos y campos para probar si el archivo era correcto o no.
Puedes imaginar la pesadilla de las expresiones regulares que estoy teniendo en este momento. Además, cada proveedor necesita muchas modificaciones a las expresiones regulares que tiendo a construir un analizador para cada proveedor.
Preguntas:
1- ¿Es esta la mejor práctica para analizar archivos (usando expresiones regulares)?
2- ¿Existe una mejor solución para analizar archivos (tal vez hay una solución preparada)? ¿Podrá mostrar qué segmento falta o si el archivo está dañado?
3- Si tengo que construir mi analizador de todos modos, ¿qué patrón de diseño o metodología debo usar?
Notas:
Leí en alguna parte sobre yacc y ANTLR, ¡pero no sé si satisfacen mis necesidades o no!
fuente
Respuestas:
Lo que necesitas es un verdadero analizador. Las expresiones regulares manejan lexing, no análisis. Es decir, identifican tokens dentro de su flujo de entrada. El análisis es el contexto de los tokens, es decir, quién va a dónde y en qué orden.
La herramienta de análisis clásica es yacc / bison . El lexer clásico es lex / flex . Como php permite la integración del código C , puede usar flex y bison para construir su analizador, hacer que php lo llame en el archivo / flujo de entrada y luego obtenga sus resultados.
Será increíblemente rápido y será mucho más fácil trabajar con él una vez que comprenda las herramientas . Sugiero leer Lex y Yacc 2nd Ed. de O'Reilly. Por ejemplo, he configurado un proyecto flex y bison en github , con un archivo MAKE. Es de compilación cruzada para Windows si es necesario.
Que es compleja, pero a medida que se enteraron, lo que necesita hacer es compleja. Hay una gran cantidad de "cosas" que se deben hacer para que un analizador funcione correctamente, y el trato flexible y bisonte con las brocas mecánicas. De lo contrario, se encontrará en la posición poco envidiable de escribir código en la misma capa de abstracción que el ensamblado.
fuente
ouch .. 'verdadero' analizador? máquinas de estado?
lo siento, pero me convertí de académico a pirata informático desde que comencé mi empleo ... por lo que diría que hay formas más fáciles ... aunque tal vez no sea 'refinado' académicamente :)
Intentaré ofrecer un enfoque alternativo con el que algunos puedan o no estar de acuerdo, pero PUEDE ser muy práctico en un entorno de trabajo.
Me gustaría;
a partir de ahí usaría clases para los tipos de datos. dividir separadores de componentes y elementos e iterar sobre las matrices devueltas.
Para mí, esto es reutilización de código, OO, baja cohesión y altamente modular ... y fácil de depurar y programar. Más simple es mejor.
para analizar un archivo no necesita máquinas de estado ni nada completamente complicado ... las máquinas de estado son muy adecuadas para analizar el código, se sorprenderá de lo poderoso que puede ser el código pseduo anterior cuando se usa en un contexto OO.
PD. He trabajado con archivos muy similares antes :)
Más pseudocódigo publicado aquí:
clase
entonces podrías usarlo así ...
y digamos que tiene más de un segmento ... use una cola para agregarlos y obtenga el primero, segundo, etc. según lo necesite. Realmente solo representa el mensaje en un obj y le da a los objetos métodos para llamar a los datos. podría aprovechar esto creando también métodos personalizados ... para la herencia ... bueno, esa es una pregunta diferente y creo que podría aplicarla fácilmente si la entiende
fuente
recognize X token and do Y
. No hay contexto, no puede tener múltiples estados, pasar un número trivial de casos hincha el código y el manejo de errores es difícil. Creo que he necesitado estas características en el mundo real en casi todos los casos. Eso deja de lado los errores a medida que crece la complejidad. La parte más difícil es configurar un esqueleto y aprender cómo funciona la herramienta. Supera eso y es igual de rápido preparar algo.parseUNAsegemntForVendor1()
,parseUNAsegemntForVendor2()
,parseUNAsegemntForVendor3()
, ... etc), ¿verdad?¿Has intentado buscar en Google "PHP EDIFACT"? Este es uno de los primeros resultados que apareció: http://code.google.com/p/edieasy/
Si bien puede no ser suficiente para su caso de uso, es posible que pueda obtener algunas ideas. No me gusta el código con sus muchos bucles y condiciones anidados, pero puede ser un comienzo.
fuente
Bueno, desde que se mencionó a Yacc / Bison + Flex / Lex, también podría incluir una de las otras alternativas principales: los combinadores de analizador sintáctico. Estos son populares en la programación funcional como con Haskell, pero si puede interactuar con el código C, puede usarlos y, qué sabe, alguien también escribió uno para PHP. (No tengo experiencia con esa implementación en particular, pero si funciona como la mayoría de ellos, debería ser bastante agradable).
El concepto general es que comience con un conjunto de analizadores pequeños y fáciles de definir, generalmente tokenizadores. Como si tuviera una función de analizador para cada uno de los 6 elementos de datos que mencionó. Luego, usa combinadores (funciones que combinan funciones) para crear analizadores más grandes que agarran elementos más grandes. Como un segmento opcional sería el
optional
combinador que opera en el analizador de segmentos.No estoy seguro de qué tan bien funciona en PHP, pero es una forma divertida de escribir un analizador y disfruto mucho usarlo en otros idiomas.
fuente
en lugar de jugar con expresiones regulares, crea tu propia máquina de estados
esto será más legible (y podrá tener mejores comentarios) en situaciones no triviales y será más fácil de depurar que el recuadro negro que es regex
fuente
No sé qué quieres hacer exactamente con estos datos después y si no es un mazo para un loco, pero tuve buenas experiencias con Eli . Describe las frases léxicas y luego la sintaxis concreta / abstracta y genera lo que desea generar.
fuente