J'essaie de trouver une meilleure solution pour faire un analyseur à certains des formats de fichiers célèbres tels que: EDIFACT et TRADACOMS .
Si vous n'êtes pas familier avec ces normes, consultez cet exemple de Wikipedia:
Voir ci-dessous pour un exemple de message EDIFACT utilisé pour répondre à une demande de disponibilité de produit: -
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'
Le segment UNA est facultatif. S'il est présent, il spécifie les caractères spéciaux à utiliser pour interpréter le reste du message. Il y a six caractères suivant UNA dans cet ordre:
- séparateur d'éléments de données de composant (: dans cet exemple)
- séparateur d'éléments de données (+ dans cet exemple)
- notification décimale (. dans cet exemple)
- libérer le caractère (? dans cet exemple)
- réservé, doit être un espace
- terminateur de segment ('dans cet exemple)
Comme vous pouvez le voir, ce ne sont que des données formatées d'une manière spéciale qui attendent d'être analysées (un peu comme les fichiers XML ).
Maintenant, mon système est construit sur PHP et j'ai pu créer un analyseur utilisant des expressions régulières pour chaque segment, mais le problème n'est pas que tout le monde implémente parfaitement la norme.
Certains fournisseurs ont tendance à ignorer complètement les segments et champs facultatifs. D'autres peuvent choisir d'envoyer plus de données que d'autres. C'est pourquoi j'ai été obligé de créer des validateurs pour les segments et les champs pour tester si le fichier était correct ou non.
Vous pouvez imaginer le cauchemar des expressions régulières que j'ai en ce moment. De plus, chaque fournisseur a besoin de nombreuses modifications des expressions régulières que j'ai tendance à construire un analyseur pour chaque fournisseur.
Des questions:
1- Est-ce la meilleure pratique pour analyser des fichiers (en utilisant des expressions régulières)?
2- Existe-t-il une meilleure solution pour analyser les fichiers (peut-être existe-t-il une solution toute faite)? Sera-t-il capable de montrer quel segment est manquant ou si le fichier est corrompu?
3- Si je dois quand même construire mon analyseur, quel modèle de conception ou méthodologie dois-je utiliser?
Remarques:
J'ai lu quelque part sur yacc et ANTLR, mais je ne sais pas s'ils correspondent à mes besoins ou non!
la source
Réponses:
Ce dont vous avez besoin est un véritable analyseur. Les expressions régulières gèrent le lexing, pas l'analyse. Autrement dit, ils identifient les jetons dans votre flux d'entrée. L'analyse est le contexte des jetons, c'est-à-dire qui va où et dans quel ordre.
L'outil d'analyse classique est yacc / bison . Le lexer classique est lex / flex . Depuis php permet intégrer du code C , vous pouvez utiliser flex et bison pour construire votre analyseur, demander à php de l'appeler sur le fichier / flux d'entrée, puis obtenir vos résultats.
Il sera extrêmement rapide et beaucoup plus facile à travailler une fois que vous aurez compris les outils . Je suggère de lire Lex et Yacc 2nd Ed. d'O'Reilly. Par exemple, j'ai mis en place un projet flex et bison sur github , avec un makefile. Il est compilable en croix pour les fenêtres si nécessaire.
Il est complexe, mais comme vous avez découvert, ce que vous devez faire est complexe. Il y a beaucoup de "trucs" qui doivent être faits pour un analyseur fonctionnant correctement, et flex et bison s'occupent des mors mécaniques. Sinon, vous vous retrouvez dans la position peu enviable d'écrire du code dans la même couche d'abstraction que l'assembly.
la source
aïe .. 'vrai' analyseur? machines d'état ??
désolé mais j'ai été converti d'universitaire à un pirate informatique depuis que j'ai commencé mon emploi .. donc je dirais qu'il existe des moyens plus faciles .. bien que peut-être pas aussi `` raffinés '' académiquement :)
J'essaierai de proposer une approche alternative avec laquelle certains peuvent ou non être d'accord mais cela PEUT être très pratique dans un environnement de travail.
Je voudrais;
à partir de là, j'utiliserais des classes pour les types de données. séparer les séparateurs de composants et d'éléments et parcourir les tableaux renvoyés.
Pour moi, c'est une réutilisation de code, OO, une faible cohésion et hautement modulaire .. et facile à déboguer et à programmer. plus c'est simple, mieux c'est.
pour analyser un fichier, vous n'avez pas besoin de machines d'état ou de tout ce qui est complètement compliqué.
ps. j'ai déjà travaillé avec des fichiers très similaires :)
Plus de pseudo code posté ici:
classe
vous pouvez ensuite l'utiliser comme ça ..
et dites que vous avez plus d'un segment .. utilisez une file d'attente pour les ajouter et obtenez le premier, le second, etc. selon vos besoins. Vous représentez vraiment le msg dans un obj et donnez aux méthodes objet d'appeler les données. vous pouvez en profiter en créant également des méthodes personnalisées .. pour l'héritage .. eh bien c'est une question différente et je pense que vous pourriez facilement l'appliquer si vous la comprenez
la source
recognize X token and do Y
. Il n'y a pas de contexte, vous ne pouvez pas avoir plusieurs états, dépasser un nombre trivial de cas alourdit le code et la gestion des erreurs est difficile. Je trouve que j'ai eu besoin de ces fonctionnalités dans le monde réel dans presque tous les cas. Cela laisse de côté des erreurs à mesure que la complexité augmente. La partie la plus difficile est de mettre en place un squelette et d'apprendre comment l'outil fonctionne. Dépassez cela et il est tout aussi rapide de préparer quelque chose.parseUNAsegemntForVendor1()
,parseUNAsegemntForVendor2()
,parseUNAsegemntForVendor3()
, ... etc), non?Avez-vous essayé de googler pour "PHP EDIFACT"? C'est l'un des premiers résultats qui est apparu: http://code.google.com/p/edieasy/
Bien que cela ne soit pas suffisant pour votre cas d'utilisation, vous pourrez peut-être en tirer quelques idées. Je n'aime pas le code avec ses nombreuses boucles et conditions imbriquées, mais cela peut être un début.
la source
Eh bien, depuis que Yacc / Bison + Flex / Lex ont été mentionnés, je pourrais aussi bien utiliser l'une des autres alternatives majeures: les combinateurs d'analyseurs. Ceux-ci sont populaires dans la programmation fonctionnelle comme avec Haskell, mais si vous pouvez vous interfacer avec du code C, vous pouvez les utiliser et, que savez-vous, quelqu'un en a également écrit un pour PHP. (Je n'ai aucune expérience avec cette implémentation particulière, mais si cela fonctionne comme la plupart d'entre eux, cela devrait être plutôt sympa.)
Le concept général est que vous commencez avec un ensemble de petits analyseurs faciles à définir, généralement des tokeniseurs. Comme si vous aviez une fonction d'analyseur pour chacun des 6 éléments de données que vous avez mentionnés. Ensuite, vous utilisez des combinateurs (fonctions qui combinent des fonctions) pour créer de plus grands analyseurs qui saisissent des éléments plus grands. Comme un segment facultatif, le
optional
combinateur opère sur l'analyseur de segment.Je ne sais pas si cela fonctionne bien en PHP, mais c'est une façon amusante d'écrire un analyseur et j'aime beaucoup les utiliser dans d'autres langues.
la source
au lieu de jouer avec les regex, créez votre propre machine d'état
ce sera plus lisible (et pourra avoir de meilleurs commentaires) dans des situations non triviales et sera plus facile à déboguer que la boîte noire qui est regex
la source
Je ne sais pas ce que vous voulez faire exactement avec ces données par la suite et si ce n'est pas un marteau pour un écrou, mais j'ai eu de bonnes expériences avec eli . Vous décrivez les phrases lexicales puis la syntaxe concrète / abstraite et générez ce que vous voulez générer.
la source