Estou tentando encontrar uma solução melhor para fazer um analisador para alguns dos famosos formatos de arquivo existentes, como: EDIFACT e TRADACOMS .
Se você não estiver familiarizado com esses padrões, verifique este exemplo da Wikipedia:
Veja abaixo um exemplo de uma mensagem EDIFACT usada para responder a uma solicitação de disponibilidade do produto: -
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'
O segmento UNA é opcional. Se presente, especifica os caracteres especiais que devem ser usados para interpretar o restante da mensagem. Existem seis caracteres após UNA nesta ordem:
- separador de elemento de dados do componente (: neste exemplo)
- separador de elemento de dados (+ neste exemplo)
- notificação decimal (. neste exemplo)
- caractere de liberação (? neste exemplo)
- reservado, deve ser um espaço
- terminador de segmento ('neste exemplo)
Como você pode ver, são apenas alguns dados formatados de uma maneira especial, esperando para serem analisados (como arquivos XML ).
Agora, meu sistema é construído em PHP e eu consegui criar um analisador usando expressões regulares para cada segmento, mas o problema é que nem todo mundo implementa o padrão perfeitamente.
Alguns fornecedores tendem a ignorar totalmente segmentos e campos opcionais. Outros podem optar por enviar mais dados do que outros. Por isso fui forçado a criar validadores para segmentos e campos para testar se o arquivo estava correto ou não.
Você pode imaginar o pesadelo das expressões regulares que estou tendo agora. Além disso, cada fornecedor precisa de muitas modificações nas expressões regulares que tendem a criar um analisador para cada fornecedor.
Questões:
1- Essa é a melhor prática para analisar arquivos (usando expressões regulares)?
2- Existe uma solução melhor para a análise de arquivos (talvez exista uma solução pronta para uso)? Será capaz de mostrar qual segmento está faltando ou se o arquivo está corrompido?
3- Se eu tiver que construir meu analisador de qualquer maneira, qual padrão ou metodologia de design devo usar?
Notas:
Eu li em algum lugar sobre yacc e ANTLR, mas não sei se eles correspondem às minhas necessidades ou não!
fonte
Respostas:
O que você precisa é de um verdadeiro analisador. Expressões regulares manipulam lexing, não analisando. Ou seja, eles identificam tokens no seu fluxo de entrada. A análise é o contexto dos tokens, ou seja, quem vai aonde e em que ordem.
A ferramenta de análise clássica é o yacc / bison . O lexer clássico é lex / flex . Como o php permite a integração do código C , você pode usar o flex e o bison para criar seu analisador, fazer com que o php o chame no arquivo / fluxo de entrada e obtenha seus resultados.
Será rápido demais e muito mais fácil trabalhar com você depois de entender as ferramentas . Sugiro ler Lex e Yacc 2nd Ed. de O'Reilly. Por exemplo, eu configurei um projeto flex e bison no github , com um makefile. É compilável para janelas, se necessário.
Ele é complexo, mas como você descobriu, o que você precisa fazer é complexa. Há uma grande quantidade de "coisas" que devem ser feitas para um analisador que funcione corretamente, e o flex e o bison lidam com os bits mecânicos. Caso contrário, você se encontrará na posição inviável de escrever código na mesma camada de abstração que a montagem.
fonte
ai .. analisador 'true'? máquinas de estado ??
desculpe, mas eu fui convertido de acadêmico para hacker desde que comecei meu emprego .. então eu diria que existem maneiras mais fáceis .. embora talvez não seja tão "refinado" academicamente :)
Tentarei oferecer uma abordagem alternativa com a qual alguns possam concordar ou não, mas PODE ser muito prático em um ambiente de trabalho.
Eu gostaria;
a partir daí eu usaria classes para os tipos de dados. separando componentes e elementos e iterando sobre as matrizes retornadas.
Para mim, isso é reutilização de código, OO, baixa coesão e altamente modular .. e fácil de depurar e programar. mais simples é melhor.
Para analisar um arquivo, você não precisa de máquinas de estado ou de qualquer coisa totalmente complicada. As máquinas de estado são bem adequadas para analisar código, você ficará surpreso com o quão poderoso o código pseduo acima pode ser quando usado em um contexto OO.
ps. Eu trabalhei com arquivos muito semelhantes antes :)
Mais pseudo-código postado aqui:
classe
você pode usá-lo assim ..
e diga que você tem mais de um segmento. use uma fila para adicioná-los e obter o primeiro, o segundo etc. conforme necessário. Você está realmente apenas representando a mensagem em um objeto e fornecendo métodos para chamar os dados. você pode tirar vantagem disso criando também métodos personalizados .. para herança .. bem, essa é uma pergunta diferente e eu acho que você poderia aplicá-la facilmente se entender
fonte
recognize X token and do Y
. Não há contexto, você não pode ter vários estados, passar de um número trivial de casos incha o código e o tratamento de erros é difícil. Acho que precisei desses recursos no mundo real em quase todos os casos. Isso deixa de lado erros à medida que a complexidade aumenta. A parte mais difícil é montar um esqueleto e aprender como a ferramenta funciona. Supere isso e é tão rápido quanto preparar algo.parseUNAsegemntForVendor1()
,parseUNAsegemntForVendor2()
,parseUNAsegemntForVendor3()
, ... etc), certo?Você já tentou pesquisar no "PHP EDIFACT"? Este é um dos primeiros resultados que apareceram: http://code.google.com/p/edieasy/
Embora possa não ser suficiente para o seu caso de uso, você poderá obter algumas idéias. Não gosto do código com muitos aninhados para loops e condições, mas pode ser um começo.
fonte
Bem, desde que o Yacc / Bison + Flex / Lex foi mencionado, eu também poderia usar uma das outras principais alternativas: combinadores de analisadores. Eles são populares na programação funcional, como no Haskell, mas se você pode fazer interface com o código C, pode usá-los e, como você sabe, alguém escreveu um para o PHP também. (Não tenho experiência com essa implementação específica, mas se funcionar como a maioria delas, deve ser bastante agradável.)
O conceito geral é que você comece com um conjunto de analisadores pequenos e fáceis de definir, geralmente tokenizadores. Como se você tivesse uma função de analisador para cada um dos 6 elementos de dados mencionados. Em seguida, você usa combinadores (funções que combinam funções) para criar analisadores maiores que capturam elementos maiores. Como um segmento opcional, seria o
optional
combinador operando no analisador de segmentos.Não tenho certeza de como ele funciona bem em PHP, mas é uma maneira divertida de escrever um analisador e eu gosto muito de usá-lo em outras linguagens.
fonte
em vez de mexer com expressões regulares, crie sua própria máquina de estado
isso será mais legível (e poderá ter melhores comentários) em situações não triviais e será mais fácil depurar que a caixa preta que é regex
fonte
Não sei o que você deseja fazer exatamente com esses dados depois e se não for uma marreta para uma porca, mas tive boas experiências com eli . Você descreve as frases lexicais e, em seguida, sintaxe concreta / abstrata e gera o que deseja gerar.
fonte