このタイプのパーサーの名前、または存在しない理由


27

従来のパーサーは入力全体を消費し、単一の解析ツリーを生成します。私は、連続ストリームを消費して解析フォレストを生成するものを探しています[ 編集:この用語の使用が型破りな理由に関するコメントの議論を参照してください ]。私の腸は、私がそのようなパーサーを最初に必要とする(または必要だと思う)ことはできないと言っていますが、私は何ヶ月も何度も検索しました。

私はXYの問題に陥る可能性があることを認識しています。私の最終的な目的は、テキストストリームを解析し、そのほとんどを無視し、認識されたセクションから解析ツリーのストリームを生成することです。

したがって、私の質問は条件付きです:これらの特性を持つパーサーのクラスが存在する場合、それは何と呼ばれますか? もしそうでなければ、なぜですか? 代替手段は何ですか?おそらく、私は従来のパーサーに私が望むことをさせる方法をいくつか逃しています。


1
基本的に、パーサーは単一のドキュメントを解析し、解析ツリーを生成し、すぐに別のドキュメントの解析を開始します。この動作の変更は、単一のドキュメントに適用されるさまざまな解析手法と比較すると簡単です。したがって、特別な用語がありません。
9000 14年

3
「Parse Forest」でGoogle検索を行ったところ、Earley Parserがそれらを生成していることがわかりました。
ロバートハーヴェイ14年

7
モナドのパーサコンビネータ、つまり、いくつかの小さなパーサで構成された大きなパーサをお探しですか。ある言語の「島」が別の言語に埋め込まれている場合に便利です。C#デザインチームの元同僚であるLuke Hobanには、次の優れた記事があります:blogs.msdn.com/b/lukeh/archive/2007/08/19/…–
Eric Lippert

3
混乱があります。ストリーム内の各ドキュメントの解析ツリーが必要であり、それらが一緒に解析フォレストを形成するということですか?これは、構文解析フォレストの通常の意味ではありません。解析フォレストは、さまざまな方法で解析できる、1つのあいまいなドキュメント(少し簡略化)の解析ツリーのセットです。そして、それこそがすべての答えの目的です。ストリームは、ゴミで区切られた多くの完全なドキュメントで構成されていますか、それとも部分的に文字化けした単一のドキュメントです。あなたの文書は構文的に正しいはずですか?適切な技術的答えはそれに依存します。
babou 14年

1
次に、解析フォレスト、およびEarley、GLR、Marpa、派生物に関するすべての回答を忘れます。別の理由が現れない限り、彼らは明らかにあなたが望むものではありません。文書は構文的に正しいですか?一部の解析手法では、部分的に文字化けしたドキュメントのコンテキストを再作成できます。これらのドキュメントの正確な構文はありますか?すべて同じですか?構文解析ツリーが本当に必要ですか、それともドキュメントを分離することで満足し、後でそれらを個別に解析する可能性がありますか?何があなたの処理を改善できるかは知っていると思いますが、それをすぐに入手できるかどうかはわかりません。
babou 14年

回答:


48

入力全体が消費される前に(部分的な)結果を返すパーサーは、増分パーサーと呼ばれます。入力の後半でのみ決定される文法に局所的なあいまいさが存在する場合、インクリメンタル解析は困難な場合があります。別の難点は、まだ到達していない解析ツリーの部分を偽装することです。

考えられるすべての解析ツリーのフォレストを返す、つまり、あいまいな文法の考えられる派生ごとに解析ツリーを返すパーサーが呼び出されます。Marpaパーサージェネレーターがこれを実行できることは知っていますが、EarleyまたはGLRベースのパーサーはこれを実行できるはずです。


しかし、あなたはそれを望んでいないようです。複数の埋め込みドキュメントを含むストリームがあり、その間にゴミがあります:

 garbagegarbage{key:42}garbagegarbage[1,2,3]{id:0}garbage...

ガベージをスキップし、(遅延して)各ドキュメントのASTのシーケンスを生成するパーサーが必要なようです。これ、最も一般的な意味ではインクリメンタルパーサーと見なすことができます。しかし、実際には次のようなループを実装します。

while stream is not empty:
  try:
    yield parse_document(stream at current position)
  except:
    advance position in stream by 1 character or token

このparse_docment場合、関数は従来の非増分パーサーになります。解析を成功させるために十分な入力ストリームを確実に読み取ることは、わずかな困難を伴います。これを処理する方法は、使用しているパーサーのタイプによって異なります。可能性としては、特定の解析エラーでバッファを増やすことや、遅延トークン化を使用することが含まれます。

遅延トークン化は、おそらく入力ストリームのために最もエレガントなソリューションです。字句解析フェーズがトークンの固定リストを生成する代わりに、パーサーは字句解析コールバックから次のトークンを遅延的に要求します[1]。レクサーは、必要なだけストリームを消費します。このように、パーサーは、ストリームの実際の終わりに到達したとき、または実際の解析エラーが発生したとき(つまり、ガベージ中に解析を開始したとき)にのみ失敗します。

[1]コールバック駆動型の字句解析器は、他のコンテキストでも同様に良い考えです。これにより、最長トークンのマッチングに関するいくつかの問題を回避できるからです。

検索しているドキュメントの種類がわかっている場合は、有望な場所でのみ停止するようにスキップを最適化できます。たとえば、JSONドキュメントは常に文字{またはで始まります[。したがって、ガベージはこれらの文字を含まない文字列です。


5
あなたの擬似コードは実際に私がやっていることですが、私はそれはjustいハックだと思いました。パーサーは2種類の例外(NO_MATCHおよびUNDERFLOW)をスローします。これにより、ストリームの位置を進めるか、さらに入力を待つかを区別できます。
ケビンクルムウィーデ14年

5
@Kevin:私もこれをいくつかの安全機能とともに使用して、ネットワークからの着信データを独自の形式で処理します。それについてハッキーなことは何もありません!
モニカーと明度レース

5

これを行うパーサーには、特定の名前はありません。しかし、これを行う1つのアルゴリズムを強調します:導関数による解析

入力を1トークンずつ消費します。入力の最後に解析フォレストを生成します。または、解析中に解析フォレスト全体を取得することもできます(部分解析)。

派生物を使用した構文解析は、文脈自由文法を処理し、あいまいな文法の構文解析フォレストを生成します。

それは本当にエレガントな理論ですが、まだ始まったばかりであり、広く展開されていません。Matt Mightには、Scala / Racket / etcのさまざまな実装へのリンクのリストがあります。

派生物での認識から始める(つまり、言語の派生物を取得することから始めて、入力を認識してそれが有効かどうかを判断する)場合、理論は学習しやすくなり、派生物で解析するようにプログラムを変更します(つまり、言語の導関数を取得する代わりに、パーサーの導関数を取得し、解析フォレストを計算します)。


4
ダウンボーター:ダウンボーターに値するものを説明してください。修正または改善する必要があるものがある場合は、知っておくといいでしょう。
トウモロコシ茎

私はダウンボーターではなく、コメントなしでダウンボーティングを夢見ることはありません。しかし、あなたの熱狂的な論文は、複雑さとフォレストの解析に関して、同じ結果を達成する多くの既存のパーサーに言及していません。関数型プログラミングは素晴らしいが、結果を主題に関する既存の文献と比較するのもいい。解析フォレストは、今後の使用にどの程度便利ですか?
babou 14年

@babou:記録のために、私はそのブログ/論文の著者ではありません。しかし、はい、このアルゴリズムを他のアルゴリズムと比較して詳細を追加し、詳細に説明できることに同意します。マット・マイトはそれについて完全な講義をしていますが、それをこの答えに統合することは素晴らしいことです。時間があれば、この答えを拡大してみます。
Cornstalks 14年

1
拡張に時間をかけすぎないでください。私が知る限り、それはOPの目的ではありません。彼の質問は注意深く読む必要があります。パースフォレストの彼の使用はあなたのものではありません。--デリバティブについて...面白くなければならないように思えますが、それを以前の作品に関連付ける必要があります...そして、その重要な部分があります。しかし、私はこの答えではなく、M Mightの論文、または彼のブログを意味しています。
babou 14年

2

理想からはほど遠いですが、私はそれが複数回行われているのを見ました:各入力行で解析してみてください。失敗した場合は、行を保持して次の行を追加します。擬似コードで:

buffer = ''
for each line from input:
    buffer = buffer + line
    if can parse buffer:
        emit tree
        buffer = ''

大きな問題は、一部の言語では次の行を読む前に式が完全かどうかを知ることができないことです。その場合、次のものを読んで、それが有効な始まりであるか、有効な継続であるかを確認できるようです...しかし、そのためには正確な言語構文が必要です

さらに悪いことに、これらの言語では、単一の長いステートメントでなくても、ファイルの終わりまで解析できない病理学的なケースを作成することは難しくありません。


0

一言で言えば

問題の迅速な解決策は、ドキュメントのすべての可能な始まりを認識するREGEXまたはFSA(有限状態オートマトン)を定義することであるようです(実際にはドキュメントに対応しない偽陽性は許可されます)。その後、入力で非常に高速に実行して、ドキュメントがエラーなしで開始できる次の場所を特定できます。ドキュメントの開始位置が誤っている場合がありますが、パーサーによって認識され、破棄されます。

したがって、Finite State Automatonがあなたが探していたパーサー名かもしれません。:)

問題

特に語彙に多くの解釈がある場合、実際の問題を理解することは常に困難です。単語解析フォレストは、いくつかの解析ツリーを持つあいまいな文のコンテキストフリー(CF)解析のために作られました(afaik)。文章のラティスの構文解析、または他のタイプの文法に多少一般化できます。したがって、Earley、GLR、Marpa、および派生パーサー(他にも多くあります)に関するすべての回答は、この場合は関係ありませんでした。

しかし、それは明らかにあなたが考えていることではありません。明確なドキュメントのシーケンスである一意の文字列を解析し、ドキュメントの構文がどのように定義されているかを実際に言っていないため、それぞれ、または何らかの構造化表現の解析ツリーを取得したい正式な言語の観点。あなたが持っているのは、ドキュメントの先頭で開始されたときに解析ジョブを実行するアルゴリズムとテーブルです。だからそれ。

実際の問題は、ドキュメントのストリームに、ドキュメントを分離するかなりのゴミが含まれていることです。そして、あなたの困難は、このゴミを十分に速くスキャンすることであるように思われます。現在の手法は、最初から開始し、最初の文字からスキャンを試行し、ドキュメント全体がスキャンされるまで、失敗するたびに次の文字での再起動にスキップします。次に、スキャンしたばかりのドキュメントの後の最初の文字から繰り返すことを繰り返します。

それは、@ amonが彼の答えの第2部で提案した解決策でもあります

パーサーのコードがドキュメントの先頭で非常に効率的に開始されるように最適化される可能性は低いため、これは非常に高速なソリューションではない場合があります(テストする方法はありません)。通常の使用では、これは一度だけ行われるため、最適化の観点からはホットスポットではありません。したがって、このソリューションでのあなたの適度な幸福は驚くことではありません。

したがって、本当に必要なのは、大量のゴミで始まるドキュメントの先頭をすばやく見つけることができるアルゴリズムです。そして、あなたは幸運です。そのようなアルゴリズムは存在します。そして、私はあなたがそれを知っていると確信しています:それは正規表現の検索と呼ばれます。

シンプルなソリューション

あなたがしなければならないことは、ドキュメントの仕様を分析して、これらのドキュメントがどのように始まるかを見つけることです。構文仕様がどのように正式に編成されているのかわからないので、その方法を正確に説明することはできません。おそらくそれらはすべて、有限のリストからの単語で始まり、おそらくいくつかの句読点や数字と混ざっています。それはあなたが確認するためのものです。

あなたがしなければならないのは、ドキュメントの最初の数文字を認識することができる有限状態オートマトン(FSA)、または同等にほとんどのプログラマーに対して正規表現(REGEX)を定義することです。大きい(時間がかかるため)これは、ドキュメントの仕様から比較的簡単に行うことができ、おそらくドキュメントの仕様を読み取るプログラムで自動的に実行できます。

正規表現を作成したら、次のように入力ストリームで実行して、最初の(または次の)ドキュメントの先頭にすばやく移動できます。

私が想定しています
- docstartすべての文書の先頭にマッチする正規表現である
- search(regex, stream)検索という機能であるstreamストリングのため一致していることregex。返されると、ストリームは最初に一致するサブストリングの先頭から始まるサフィックスサブストリームに縮小されるか、空のストリームに一致が検出されません。
- parse(stream)ストリームの最初(ドキュメントの残り)からドキュメントの解析を試み、解析ツリーを任意の形式で返すか、失敗します。戻ると、解析されたドキュメントの終わりの直後の位置から始まるサフィックスサブストリームにストリームが縮小されます。解析が失敗した場合、例外を呼び出します。

forest = empty_forest
search(docstart, stream)
while stream is not empty:
  try:
    forest = forest + parse(stream)
  except
    remove first character from stream
  search(docstart, stream)

次の検索で同じ一致が再び検出されないように、最初の文字を削除する必要があることに注意してください。

もちろん、ストリームの短縮はイメージです。ストリームのインデックスにすぎない場合があります。

最後の注意点は、すべての始まりを認識している限り、正規表現はあまり正確である必要はないということです。文書の先頭にできない文字列(誤検知)をときどき認識する場合、唯一のペナルティは、パーサーへの1回の無駄な呼び出しのコストです。

したがって、有用な場合は、正規表現の簡素化に役立つ可能性があります。

より高速なソリューションの可能性について

上記のソリューションは、ほとんどの場合、かなりうまく機能するはずです。ただし、大量のゴミとテラバイトのファイルを処理する必要がある場合は、より高速に実行される他のアルゴリズムがある可能性があります。

このアイデアは、ボイヤー・ムーアの文字列検索アルゴリズムに由来しています。このアルゴリズムは、文字列の構造分析を使用してほとんどのストリームの読み取りをスキップし、フラグメントを見ずにジャンプするため、単一のストリングのストリームを非常に高速に検索できます。これは、単一の文字列に対する最速の検索アルゴリズムです。

難点は、単一の文字列ではなく、検索正規表現への適応が非常にデリケートであり、検討している正規表現の機能によってはうまく機能しない可能性があることです。これは、解析するドキュメントの構文に依存する可能性があります。しかし、私が見つけた文書を注意深く読む時間がないので、これについて私をあまり信用しないでください。

私はあなたにウェブ上で見つけた1つまたは2つのポインタを残しています、これは明らかに査読された研究論文であるものを含みますが、これはよりパフォーマンスの問題がある場合にのみ考慮されるより推測的で、おそらく研究的であるとみなすべきです。そして、おそらくそれを行うシェルフプログラムはありません。


-2

あなたが説明していることは、SAX対SOMとして説明できます。

SAX-(XML用のシンプルなAPI)は、XMLドキュメント用のXML-DEVメーリングリストによって開発されたイベントシーケンシャルアクセスパーサーAPIです。

SOM-(XML Schema Object Model)XMLファイルのメモリ表現へのランダムアクセス

C#とJavaには両方のタイプの実装があり、おそらくもっと多くの実装があります。通常、XSDまたはDTDはオプションです。

SAXの利点は、メモリオーバーヘッドが低いことです。これは、大きなXMLファイルに最適です。トレードオフは、SAXを使用したランダムアクセスが存在しないか低速であるということです。通常、SOMを使用する場合よりも開発時間がかなり長くなります。SOMの明らかな問題は、潜在的に大きなRAM要件です。

この回答は、すべてのプラットフォームおよびすべての言語に適用されるわけではありません。


1
OPがXMLを解析していると思うのはなぜですか?
ダンピチェルマン14年

1
これは質問に答えません。

@Snowmanこれまでのところ、受け入れられた答えの前半を含めて、ほとんど何も質問に答えていませんでした。誰かを選ぶ意味はありません。質問は注意深く読む必要があります。
babou

@babou私はだれも選んでいませんでした。

@スノーマンが私の下票を説明します。それは公平であり、より多くのユーザーがそれを行うことを望みます。私はネイティブスピーカーではありません。彼を選ぶことは、あまりにも強い表現です。誰もが不当な仮定をしているというだけです。そのため、気付く価値さえありません。これは他のものよりも少し外れているように見えるのは事実です。
babou 14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.