web-dev-qa-db-ja.com

正規表現を使用してXMLおよびHTMLを解析することが難しい理由の例を提供できますか?

over および over again を作成している人の1つの間違いは、XMLまたはHTMLを正規表現で解析しようとしていることです。 XMLとHTMLの解析が難しい理由のいくつかを以下に示します。

人々はファイルを一連の行として扱いたいが、これは有効である:

<tag
attr="5"
/>

人々は<または<tagをタグの開始として扱いたいが、このようなものは野生に存在する:

<img src="imgtag.gif" alt="<img>" />

多くの場合、開始タグと終了タグを一致させたいが、XMLとHTMLにはタグを含めることができます(従来の正規表現ではまったく処理できません)。

<span id="outer"><span id="inner">foo</span></span> 

多くの場合、ドキュメントのコンテンツ(有名な「特定のページのすべての電話番号を検索する」問題など)と照合したいのですが、データはマークアップされる場合があります(表示時に正常に見えても)。

<span class="phonenum">(<span class="area code">703</span>)
<span class="prefix">348</span>-<span class="linenum">3020</span></span>

コメントには、不適切な形式のタグや不完全なタグが含まれている場合があります。

<a href="foo">foo</a>
<!-- FIXME:
    <a href="
-->
<a href="bar">bar</a>

他に知っていることはありますか?

393
Chas. Owens

以下に、有効なXMLをいくつか示します。

<!DOCTYPE x [ <!ENTITY y "a]>b"> ]>
<x>
    <a b="&y;>" />
    <![CDATA[[a>b <a>b <a]]>
    <?x <a> <!-- <b> ?> c --> d
</x>

そして、この小さな喜びの束は、有効なHTMLです。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" [
    <!ENTITY % e "href='hello'">
    <!ENTITY e "<a %e;>">
]>
    <title>x</TITLE>
</head>
    <p id  =  a:b center>
    <span / hello </span>
    &amp<br left>
    <!---- >t<!---> < -->
    &e link </a>
</body>

無効なコンストラクトに対するすべてのブラウザー固有の解析は言うまでもありません。

それに対して正規表現を頑張ってください!

編集(JörgW Mittag):整形式で有効なHTML 4.01のもう1つの素敵な部分を次に示します。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd"> 
<HTML/
  <HEAD/
    <TITLE/>/
    <P/>
259
bobince

実は

<img src="imgtag.gif" alt="<img>" />

は有効なHTMLではなく、有効なXMLでもありません。

'<'および '>'は属性文字列内の有効な文字ではないため、有効なXMLではありません。対応するXMLエンティティltを使用してエスケープする必要があります。およびgt;

HTMLでは短い終了フォームが許可されていないため、有効なHTMLでもありません(ただし、XMLおよびXHTMLでは正しいです)。 「img」タグは、HTML 4.01仕様に従って暗黙的に閉じられたタグでもあります。つまり、手動で閉じることは実際には間違っており、他のタグを2回閉じることに相当します。

HTMLの正しいバージョンは

<img src="imgtag.gif" alt="&lt;img&gt;">

xHTMLおよびXMLの正しいバージョンは

<img src="imgtag.gif" alt="&lt;img&gt;"/>

次の例も無効です

<
tag
attr="5"
/>

これも有効なHTMLまたはXMLではありません。タグの名前は '<'のすぐ後ろでなければなりませんが、属性と終了 '>'はどこでもかまいません。したがって、有効なXMLは実際には

<tag
attr="5"
/>

そして、もう1つのファンキーなものがあります。実際には、属性引用文字として「」または「」を使用することを選択できます

<img src="image.gif" alt='This is single quoted AND valid!'>

投稿された他のすべての理由は正しいですが、HTMLの解析に関する最大の問題は、通常、すべての構文規則を正しく理解していないことです。ブラウザがtagsoupをHTMLとして解釈するという事実は、あなたが実際に有効なHTMLを書いたことを意味しません。

編集:そして、stackoverflow.comでさえ、有効と無効の定義に関して私に同意します。無効なXML/HTMLは強調表示されていませんが、修正されたバージョンは強調表示されています。

基本的に、XMLは正規表現で解析されるようにはなっていません。しかし、そうする理由もありません。すべての言語には、非常に多くのXMLパーサーがあります。 SAXパーサー、DOMパーサー、およびプルパーサーから選択できます。これらはすべて、正規表現を使用した解析よりもはるかに高速であることが保証されているため、結果のDOMツリーでXPathやXSLTなどのクールなテクノロジーを使用できます。

したがって、私の返信は、XMLを正規表現で解析するのが難しいだけでなく、悪い考えでもあります。数百万ある既存のXMLパーサーの1つを使用するだけで、XMLのすべての高度な機能を利用できます。

HTMLは非常に難しいため、自分で解析することさえできません。第一に、合法的な構文には気づかないかもしれない微妙な点が多くあります。第二に、野生のHTMLは巨大な臭いの山です(あなたは私のドリフトを取得します)。タグスープのようなHTMLをうまく処理するさまざまな緩いパーサーライブラリがあります。これらを使用するだけです。

68
LordOfThePigs

このテーマに関するブログエントリ全体を書きました: 正規表現の制限

問題の核心は、HTMLとXMLが再帰構造であり、適切に解析するためにカウントメカニズムを必要とすることです。真の正規表現はカウントできません。カウントするには、文脈自由文法が必要です。

前の段落には少し注意が必要です。特定の正規表現の実装は、再帰の概念をサポートするようになりました。ただし、正規表現に再帰を追加し始めたら、実際に境界を広げているので、パーサーを検討する必要があります。

56
JaredPar

リストにない1つの落とし穴は、属性が任意の順序で表示できることです。したがって、正規表現がhref "foo"およびクラス "bar"のリンクを探している場合、属性は任意の順序で、他の任意の数を持つことができますそれらの間のもの。

20
AmbroseChapel

「解析」の意味に依存します。一般的に、XML文法は決して正規のものではないため、XMLは正規表現を使用して解析できません。簡単に言えば、正規表現ではカウントできないため(Perl正規表現では実際にカウントできる可能性があります)、開始タグと終了タグのバランスを取ることはできません。

16
Anton Gogolev

人々は実際に正規表現を使用して間違いを犯していますか、それとも彼らが達成しようとしているタスクに十分なだけですか?

他の人が答えたように、正規表現を使用してhtmlとxmlを解析することは不可能であることに完全に同意します。

ただし、html/xmlを解析するのではなく、「既知の良い」ビットのhtml/xmlの小さなデータを取得するだけの場合は、正規表現またはより単純な「サブストリング」でも十分です。

9
Robin Day

人々は通常、貪欲なパターンを書くことをデフォルトにします。多くの場合、考え抜かれていない。*がファイルの大きな塊を可能な限り最大の<foo>。* </ foo>に丸toみします。

6
chaos

「車輪を再発明しないでください」と言いたくなります。 XMLが本当にそうであることを除けば、本当に複雑なフォーマットです。したがって、「シンクロトロンを再発明しないでください」と言う必要があります。

おそらく、正しい決まり文句は「あなたが持っているものがすべてハンマーであるとき」から始まります。正規表現の使用方法を知っているので、正規表現は構文解析が得意です。

XMLの解析はhardであるためです。 XML解析ライブラリーの使用方法を学ぶ必要がないことで節約できる労力は、創造的な作業と、必要なバグの回避によって補われます。あなた自身のために、「XMLライブラリ」をグーグルで検索し、他の誰かの仕事を活用してください。

6

問題は次のように要約されると思います。

  1. 正規表現はほとんど常に間違っています。適切に入力できない合法的な入力があります。十分な努力をすれば、99%または99.999%にすることができますが、エンティティを使用することでXMLで許可されている奇妙なことのためだけに、100%にすることはほとんど不可能です。

  2. 入力の0.00001%であっても正規表現が正しくない場合、セキュリティ上の問題が発生します。誰かがアプリケーションを破壊する入力を発見できるからです。

  3. 正規表現がケースの99.99%をカバーするのに十分正しい場合、それは完全に判読できず、維持できなくなります。

  4. 中程度のサイズの入力ファイルでは、正規表現のパフォーマンスが非常に低下する可能性が非常に高くなります。私が最初にXMLに出会ったのは、着信XMLドキュメントを(誤って)解析するPerlスクリプトを適切なXMLパーサーに置き換えることでした。 10秒から約0.1秒まで。

4
Michael Kay

thisclassicには探している情報があると思います。あなたはそこのコメントの1つでポイントを見つけることができます:

ここでの欠陥は、HTMLがChomsky Type 2文法(コンテキストフリー文法)であり、RegExがChomsky Type 3文法(正規表現)であると思います。 タイプ2の文法はタイプ3の文法よりも基本的に複雑であるため、この作業を期待することはできません。しかし、多くの人が試してみて、成功を主張する人もいれば、障害を見つけてあなたを完全に台無しにする人もいます。

ウィキペディアの詳細情報: Chomsky Hierarchy

4
Adam Arold

私はこの問題に簡単な答えをしました here 。それは100%のマークを説明していませんが、前処理の仕事をする気があるなら、それがどのように可能であるかを説明します。

1
Erutan409

一般的に、XML文法は決して正規のものではないため、XMLは正規表現を使用して解析できません。簡単に言えば、正規表現ではカウントできないため(Perl正規表現では実際にカウントできる可能性があります)、開始タグと終了タグのバランスを取ることはできません。

同意しません。正規表現で再帰を使用する場合、開始タグと終了タグを簡単に見つけることができます。

ここ 最初のメッセージの例の解析エラーを回避するために、正規表現の例を示しました。

1
Maxim Suslov