web-dev-qa-db-ja.com

ファイルを解析する最良の方法

[〜#〜] edifact [〜#〜] および [〜 #〜] tradacoms [〜#〜]

これらの標準に慣れていない場合は、Wikipediaからこの例を確認してください。

製品の在庫状況のリクエストに回答するために使用される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の後に6文字あります。

  • コンポーネントデータ要素セパレータ(:このサンプルでは)
  • データ要素セパレータ(このサンプルでは+)
  • 10進数の通知(このサンプルでは。)
  • リリースキャラクター(このサンプルでは?)
  • 予約済み、スペースでなければならない
  • セグメントターミネーター(このサンプルでは ')

ご覧のように、[〜#〜] xml [〜#〜]ファイルのように、解析されるのを待っている特別な方法でフォーマットされたデータの一部です)。

現在、私のシステムはPHP=に基づいて構築されており、各セグメントの正規表現を使用してパーサーを作成できましたが、すべての人が標準を完全に実装しているわけではありません。

一部のサプライヤーは、オプションのセグメントとフィールドを完全に無視する傾向があります。他の人は他より多くのデータを送信することを選択するかもしれません。そのため、ファイルが正しいかどうかをテストするために、セグメントとフィールドのバリデーターを作成する必要がありました。

私が今持っている正規表現の悪夢を想像できます。さらに、各サプライヤは、パーサを作成する傾向がある正規表現に多くの変更を加える必要があります。


質問:

1-これは(正規表現を使用して)ファイルを解析するためのベストプラクティスですか?

2-ファイルを解析するためのより良いソリューションはありますか?どのセグメントが欠落しているか、またはファイルが破損しているかを表示できますか?

3-とにかくパーサーを構築する必要がある場合、どの設計パターンまたは方法論を使用する必要がありますか?

注:

YaccとANTLRについてどこかで読みましたが、それらが私のニーズに合っているかどうかはわかりません!

9
Songo

必要なのは真のパーサーです。正規表現は構文解析ではなく字句解析を処理します。つまり、入力ストリーム内のトークンを識別します。解析はトークンのコンテキストです。誰がどこに、どの順番で行くか。

古典的な解析ツールは yacc/bison です。古典的なレクサーは Lex/flex です。 PHPは Cコードの統合 を許可しているため、フレックスとバイソンを使用してパーサーを作成し、入力ファイル/ストリームでphpを呼び出して結果を取得できます。

それは 超高速 であり、ツールを理解するとでの作業がはるかに容易になります。 O-Reillyの Lex and Yacc 2nd Ed。 を読むことをお勧めします。例として、メイクファイルを使用して github上のflexおよびbisonプロジェクト を設定しました。必要に応じて、ウィンドウ用にクロスコンパイルできます。

それはis複雑ですが、ご存知のとおり、実行する必要があるのは複雑です。適切に機能するパーサーのために実行する必要のある「もの」はたくさんあり、フレックスとバイソンは機械的なビットを扱います。それ以外の場合は、アセンブリと同じ抽象化レイヤーでコードを書くといううらやましい立場にいます。

18
Spencer Rathbun

ouch .. 'true'パーサー?ステートマシン??

申し訳ありませんが、私は就職以来アカデミックからハッカーに転向してきました。なので、もっと簡単な方法があると思います。

私はいくつかが同意するかもしれないし、同意しないかもしれない代替のアプローチを提供しようとしますが、それは作業環境では非常に実用的です。

私は...するだろう;

loop every line
   X = pop the first 3 letters of line
   Y = rest of line
   case X = 'UNA':
       class init (Y)

そこからデータ型のクラスを使用します。コンポーネントと要素のセパレーターを分割し、返された配列を反復処理します。

私にとって、これはコードの再利用、オブジェクト指向、低凝集度、高度にモジュール化されたものであり、デバッグとプログラミングが簡単です。シンプルな方が良いです。

ファイルを解析するには、ステートマシンやまったく複雑なものは必要ありません。ステートマシンはコードの解析に適しているため、OOコンテキスト。

ps。以前に非常によく似たファイルで作業したことがある:)


ここに投稿されたその他の疑似コード:

クラス

UNA:

init(Y):
 remove ' from end
 components = Y.split(':') 
 for c in components
     .. etc..

 getComponents():
   logic..
   return

 getSomethingElse():
   logic..
   return

class UNZ:
   ...

Parser(lines):

Msg = new obj;

for line in lines
   X = pop the first 3 letters of line
   Y = rest of line
   case X = 'UNA':
      Msg.add(UNA(Y))

msg.isOK = true
return Msg

その後、このように使用できます。

msg = Main(File.getLines());
// could put in error checking
// if msg.isOK:
msg.UNA.getSomethingElse();

複数のセグメントがあると言います。必要に応じて、キューを使用してそれらを追加し、最初、2番目などを取得します。実際には、単にmsgをobjに表現し、データを呼び出すためのオブジェクトメソッドを提供しています。カスタムメソッドを作成することでこれを利用することもできます..継承について..それは別の質問です。理解すれば簡単に適用できると思います

3
Ross

「PHP EDIFACT」のグーグルを試しましたか?これは、最初に表示された結果の1つです。 http://code.google.com/p/edieasy/

ユースケースとしては十分ではないかもしれませんが、そこからいくつかのアイデアを得ることができるかもしれません。多くのforループと条件が入れ子になっているコードは好きではありませんが、最初のコードになるかもしれません。

1
chiborg

Yacc/Bison + Flex/Lexについて触れたので、他の主要な代替手段の1つであるパー​​サーコンビネーターを投入することもできます。これらはHaskellのような関数型プログラミングで人気がありますが、Cコードにインターフェースできる場合はそれらを使用できます。また、 誰かがPHPのために書いたものもあります。 (私はその特定の実装についての経験はありませんが、それがそれらのほとんどのように機能する場合、それはかなり素晴らしいはずです。)

一般的な概念は、小さな、簡単に定義できるパーサー、通常はトークナイザーのセットから始めることです。あなたが言及した6つのデータ要素のそれぞれに1つのパーサー関数があるように。次に、コンビネーター(関数を組み合わせる関数)を使用して、より大きな要素を取得するより大きなパーサーを作成します。オプションのセグメントと同様に、セグメントパーサーで動作するoptionalコンビネーターがあります。

PHPでどれだけうまく機能するかはわかりませんが、パーサーを作成する楽しい方法であり、他の言語での使用をとても楽しんでいます。

1
CodexArcanum

正規表現をいじるのではなく、独自の状態マシンを作成する

これは重要な状況ではより読みやすく(そしてより良いコメントを付けることができ)、正規表現であるブラックボックスのデバッグが容易になります

0
ratchet freak

このデータを後でどのように正確に処理したいのかわからないし、それがナットのハンマーではない場合でも、 eli で良い経験をしました。語彙句を記述し、次に具体的/抽象的な構文を記述して、生成したいものを生成します。

0
Sebastian Bauer