Я пытаюсь найти лучшее решение для создания парсера для некоторых известных форматов файлов, таких как: EDIFACT и TRADACOMS .
Если вы не знакомы с этими стандартами, посмотрите этот пример из Википедии:
Ниже приведен пример сообщения EDIFACT, используемого для ответа на запрос доступности продукта: -
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'
Сегмент UNA является необязательным. Если он присутствует, он указывает специальные символы, которые должны использоваться для интерпретации оставшейся части сообщения. В этом порядке после UNA есть шесть символов:
- разделитель элементов данных компонента (: в этом примере)
- разделитель элементов данных (+ в этом примере)
- десятичное уведомление (в этом примере)
- выпустить символ (? в этом примере)
- зарезервировано, должно быть пробелом
- терминатор сегмента (в данном примере)
Как вы можете видеть, это просто некоторые данные, отформатированные особым образом и ожидающие анализа (во многом как XML- файлы).
Теперь моя система построена на PHP, и я смог создать синтаксический анализатор с использованием регулярных выражений для каждого сегмента, но проблема не в том, что все прекрасно реализуют стандарт.
Некоторые поставщики имеют тенденцию полностью игнорировать дополнительные сегменты и поля. Другие могут отправить больше данных, чем другие. Вот почему я был вынужден создать валидаторы для сегментов и полей, чтобы проверить правильность файла или нет.
Вы можете представить себе кошмар регулярных выражений, которые у меня сейчас есть. Кроме того, каждому поставщику нужно много модификаций регулярных выражений, которые я собираю создать для каждого поставщика.
Вопросов:
1- Это лучший метод для анализа файлов (с использованием регулярных выражений)?
2- Есть ли лучшее решение для разбора файлов (может быть, есть готовое решение там)? Сможет ли он показать, какой сегмент отсутствует или файл поврежден?
3. Если мне все равно придется создавать свой парсер, какой шаблон или метод проектирования мне использовать?
Ноты:
Я где-то читал о YACC и ANTLR, но я не знаю, соответствуют ли они моим потребностям или нет!
источник
Ответы:
Что вам нужно, так это настоящий парсер. Регулярные выражения обрабатывают лексизм, а не синтаксический анализ. То есть они идентифицируют токены в вашем входном потоке. Парсинг - это контекст токенов, то есть, кто идет куда и в каком порядке.
Классический инструмент синтаксического анализа - yacc / bison . Классический лексер - это lex / flex . Поскольку php позволяет интегрировать код на C , вы можете использовать flex и bison для создания вашего парсера, сделать так, чтобы php вызвал его во входном файле / потоке, а затем получил ваши результаты.
Это будет невероятно быстро , и с ним будет намного легче работать, как только вы поймете инструменты . Я предлагаю прочитать Лекса и Яка 2-е изд. от О'Рейли. Например, я создал проект flex и bison на github с make-файлом. Это кросс-компилируется для окон, если это необходимо.
Это является сложным, но , как вы узнали, что вам нужно сделать , это комплекс. Для правильной работы синтаксического анализатора необходимо выполнить множество «мелочей», а с механическими битами разбираются гибкость и бизон. В противном случае вы окажетесь в незавидном положении написания кода на том же уровне абстракции, что и сборка.
источник
ой .. "настоящий" парсер? конечные автоматы ??
извините, но с тех пор, как я начал работать, меня превратили из академика в хакера ... поэтому я бы сказал, что есть более простые способы ... хотя, возможно, не так "утонченно" академически :)
Я попытаюсь предложить альтернативный подход, с которым некоторые могут соглашаться или не соглашаться, но он МОЖЕТ быть очень практичным в рабочей среде.
Я мог бы;
оттуда я бы использовал классы для типов данных. разделение компонентов и разделителей элементов и итерация по возвращенным массивам.
Для меня это повторное использование кода, ОО, низкая когезия и высокая модульность ... и его легко отлаживать и программировать. проще, тем лучше.
для анализа файла вам не нужны конечные автоматы или что-то совершенно сложное. конечные автоматы хорошо подходят для анализа кода, вы будете удивлены тем, насколько мощным может быть приведенный выше псевдо-код при использовании в контексте ОО.
пс. я работал с очень похожими файлами раньше :)
Более псевдокод размещен здесь:
учебный класс
Вы могли бы тогда использовать это как это ..
и скажем, у вас есть более одного сегмента .. используйте очередь, чтобы добавить их и получить первый, второй и т. д., как вам нужно. Вы на самом деле просто представляете msg в obj и предоставляете объектные методы для вызова данных. Вы можете воспользоваться этим, также создавая собственные методы ... для наследования ... ну, это другой вопрос, и я думаю, что вы могли бы легко применить его, если вы понимаете это
источник
recognize X token and do Y
. Нет контекста, вы не можете иметь несколько состояний, переходя через тривиальное число случаев, вы попадаете в код, и обработка ошибок затруднена. Я считаю, что мне нужны эти функции в реальном мире почти во всех случаях. Это оставляет в стороне ошибки по мере роста сложности. Самая сложная часть - это установка скелета и изучение работы инструмента. Преодолеть это, и это так же быстро, чтобы что-то взбодрить.parseUNAsegemntForVendor1()
,parseUNAsegemntForVendor2()
,parseUNAsegemntForVendor3()
, ... и т.д.), не так ли?Вы пробовали поискать в Google "EDIFACT PHP"? Это один из первых всплывающих результатов: http://code.google.com/p/edieasy/
Хотя этого может быть недостаточно для вашего варианта использования, вы можете получить некоторые идеи из него. Мне не нравится код с множеством вложенных циклов и условий, но это может быть началом.
источник
Ну, с тех пор как упоминались Yacc / Bison + Flex / Lex, я мог бы также добавить одну из других основных альтернатив: комбинаторы синтаксического анализа. Они популярны в функциональном программировании, как, например, в Haskell, но если вы можете взаимодействовать с кодом на C, вы можете использовать их, и, как вы знаете, кто-то написал также для PHP. (У меня нет опыта работы с этой конкретной реализацией, но если она работает, как и большинство из них, это должно быть довольно неплохо.)
Общая концепция заключается в том, что вы начинаете с набора небольших, легко определяемых парсеров, обычно токенизаторов. Как будто у вас есть одна функция парсера для каждого из 6 элементов данных, которые вы упомянули. Затем вы используете комбинаторы (функции, которые объединяют функции) для создания больших парсеров, которые захватывают большие элементы. Как необязательный сегмент будет
optional
комбинатор, работающий на синтаксическом анализаторе сегмента.Не уверен, насколько хорошо он работает в PHP, но это интересный способ написания парсера, и мне очень нравится использовать их на других языках.
источник
вместо того, чтобы возиться с регулярными выражениями, сделайте свой собственный конечный автомат
это будет более читабельным (и сможет иметь лучшие комментарии) в нетривиальных ситуациях и будет легче отлаживать, чем черный ящик, который является регулярным выражением
источник
Я не знаю, что вы хотите делать с этими данными потом, и если это не кувалда, но у меня был хороший опыт работы с eli . Вы описываете лексические фразы, а затем конкретный / абстрактный синтаксис и генерируете то, что хотите генерировать.
источник