正規表現を使用していない場合、HTML解析はどのように機能しますか?


96

HTML文字列から何かを解析または抽出する方法を尋ねる質問が毎日表示され、最初の回答/コメントは常に「RegExを使用してHTMLを解析しないでください。怒りを感じないようにしてください!」(その最後の部分は時々省略されます)。

これは私にとってかなり混乱します。一般的に、複雑な文字列を解析する最良の方法は正規表現を使用することだといつも思っていました。では、HTMLパーサーはどのように機能するのでしょうか。解析に正規表現を使用していませんか。

正規表現を使用する場合の特定の引数の1つは、解析の代替手段が常に存在するとは限らないことです(JavaScriptなど、DOMDocumentが普遍的に使用可能なオプションではない場合)。たとえば、jQueryは、正規表現を使用してHTML文字列をDOMノードに変換することで問題なく管理できるようです。

これをCWするかどうかわからない、それは私が答えたい真の質問であり、ディスカッションスレッドを意図するものではありません。


解析とhtml解析を追加するためにタグを付け直しました-@Andy E、それで問題ないことを願っています-役に立つと思いました。
JXG 2010年

@JXG:それで結構です、ありがとう:-)
アンディE

回答:


65

通常はトークナイザーを使用します。ドラフトHTML5仕様には、「実際のHTML」を処理するための広範なアルゴリズムがあります。


1
「これらのケースを処理するために、パーサーには、最初にゼロに設定する必要があるスクリプトネストレベルと、最初にfalseに設定する必要があるパーサー一時停止フラグがあります。」-つまり、あなたはそれを自分で反復処理し、カスタム・ロジックのたくさん持っている必要があります:P
ティモシーKhouriの

1
賛成票。一部のテクノロジーではなく、アルゴリズムの複雑さを強調することをお勧めします。
Arnis Lapsa

1
たくさんのカスタムロジックを使って自分で反復するのは、それほど良い考えではありません。可能であれば、標準アルゴリズムをサポートするライブラリを使用してください。例えばsearch.cpan.org/~tobyink/HTML-HTML5-Parser-0.03/lib/HTML/HTML5/... / code.google.com/p/html5lib
クエンティン・

8
HTMLパーサーの主な問題は、エラーが発生したときに「解析エラー」を吐き出してそのままにしておくことはできないということです。Quirksモードに入り、タグの不一致、[{]}スタイルのインターレース、あらゆる種類の奇妙さなど、遭遇した混乱から可能な限り最善を尽くして、結果をできるだけ美しく、不可避なものにしようとします失敗が最も痛くない...これは、正規表現でできることではありません。
SF。

7
@ティモシーK: '注:このアルゴリズムは要素を親に変更させる方法のため、「養子縁組アルゴリズム」と呼ばれています(「近親相姦アルゴリズム」を含む、ネストされていないコンテンツを処理するための他の可能なアルゴリズムとは対照的に、 「秘密事件アルゴリズム」、「ハイゼンベルクアルゴリズム」)。
JXG 2010年

133

では、HTMLパーサーはどのように機能するのでしょうか。正規表現を使用して解析しませんか?

うーん、ダメ。

計算理論のコース、またはコース、コンパイラのコース、または類似のコースを受講した場合は、さまざまな種類の言語と計算モデルがあることを思い出してください。すべての詳細を説明する資格はありませんが、主要なポイントのいくつかをあなたと一緒に確認できます。

(これらの目的で)最も単純なタイプの言語と計算は、通常の言語です。これらは正規表現で生成でき、有限オートマトンで認識できます。基本的に、これらの言語での文字列の「解析」は状態を使用しますが、補助メモリは使用しません。HTMLは通常の言語ではありません。考えてみれば、タグのリストは任意に深くネストすることができます。たとえば、テーブルにはテーブルを含めることができ、各テーブルには多くのネストされたタグを含めることができます。正規表現を使用すると、タグのペアを選択できる場合がありますが、任意にネストされたものはありません。

規則的ではない古典的な単純な言語は、正しく一致する括弧です。いつものように、常に機能する正規表現(または有限オートマトン)を構築することはできません。ネストの深さを追跡するには、メモリが必要です。

メモリ用のスタックを備えたステートマシンは、計算モデルの次の強みです。これはプッシュダウンオートマトンと呼ばれ、文脈自由文法によって生成された言語を認識します。ここで、正しく一致する括弧を認識できます。実際、スタックはそのための完璧なメモリモデルです。

さて、これはHTMLに十分ですか?残念ながら、違います。おそらく、実際にはすべてのタグが常に完全に揃っている、非常に慎重に検証されたXMLの場合があります。実際のHTMLでは、のようなスニペットを簡単に見つけることができます<b><i>wow!</b></i>。これは明らかにネストしないので、正しく解析するために、スタックは十分に強力ではありません。

次のレベルの計算は、一般的な文法によって生成され、チューリングマシンによって認識される言語です。これは一般に、存在する最強の計算モデルであると認められています-補助メモリを備えたステートマシンで、メモリはどこでも変更できます。これが、プログラミング言語でできることです。これは、HTMLが存在する複雑さのレベルです。

ここですべてを1つの文に要約するには、一般的なHTMLを解析するには、正規表現ではなく実際のプログラミング言語が必要です。

HTMLは、他の言語が解析されるのと同じ方法で解析されます:字句解析と解析。字句解析ステップは、個々の文字のストリームを意味のあるトークンに分解します。解析ステップでは、状態とメモリを使用して、トークンを組み立てて、操作可能な論理的に一貫したドキュメントにします。


22

正規表現は、パーサーの1つの形式にすぎません。正直なところHTMLパーサーは、再帰降下、予測、およびその他のいくつかの手法を使用してテキストを適切に解釈することで、正規表現で表現できるものよりもかなり複雑になります。あなたが本当にそれに入りたいなら、あなたはlex&yaccと同様のツールをチェックするかもしれません。

HTML解析に正規表現を使用することの禁止は、おそらく「HTMLを解析するために単純な正規表現を使用しないでください...」(怒りを感じないように)「...そして結果を慎重に扱ってください。特定の特定の目標については、正規表現は完全に適切である可能性がありますが、正規表現の制限に注意し、解析しているテキストのソースに適切であるように十分注意する必要があります(たとえば、ユーザー入力、実際には非常に注意してください)。


+1、良い答えです。認めざるを得ません。HTMLを制御していなくても、以前に正規表現を使用したことがありますが、公開されているどのようなアプリケーションでも使用していません。私も「怒りを感じた」のは素朴だったからです。しかし、それはずっと前のことです:-)
Andy E

6

HTMLの解析とは、線形テキストをツリー構造に変換することです。正規表現は通常、ツリー構造を処理できません。次のトークンを取得するために各ポイントで必要な正規表現は常に変化します。パーサーでは正規表現を使用できますが、可能な解析状態ごとに正規表現の配列全体が必要になります。


2

100%のソリューションが必要な場合:HTMLを1文字ずつ反復する独自のカスタムコードを作成する必要があり、現在のノードを停止して開始する必要があるかどうかを判断するための膨大なロジックが必要次。

これは有効なHTMLであるためです。

<ul>
<li>One
<li>Two
<li>Three
</ul>

しかし、これもそうです:

<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>

「90%ソリューション」で問題がない場合:次に、XMLパーサーを使用してドキュメントをロードします。または、正規表現を使用します(ただし、コンテンツのマスターである場合はxmlの方が簡単です)。


4
XMLパーサーは1%ソリューションに似ています。整形式のXMLであるHTML文書の数はごくわずかです。
Quentin

4
ええ、彼らはそうします...あなたが物事をストリーミングしようとすることができるので、文字通り「一文字ずつ」をとらないでください。しかし、私のポイントは、あなた自身のパーサーを書かなければならないということです。新しい時代のプログラマーはそのようなコードを書くことに慣れていない...私たちは "HtmlDocumentUtility.Load"やそのようなものに慣れています:)
Timothy Khouri

4
@Andy E:正規表現は魔法ではありません。他の種類の解析や他の文字列関数と同様に、文字ごとに機能します。
Bart van Heukelom、2010年

1
ところで:あなたの最初の例は単に「準有効なHTML」ではありません。実際には有効なHTML 4.01 Strictです。これを確認するには、たとえばW3Cバリデーターを使用できます。終了タグは、<li>の正式なオプションです(HTML 4仕様を参照)。
sleske 2010年

2
@バート:良い点、私の脳は時々すべての論理を忘れて、物事は魔法で機能すると考えています。
アンディE
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.