正規表現でXMLとHTMLを解析するのが難しい理由の例をいくつか挙げていただけますか?[閉まっている]


402

私が人々が何度何度も作っているのを見かける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>

他に知っている落とし穴はありますか?


14
Webブラウザーは、この種の混乱を1秒間に数百万回理解します。誰かが私たちのためにWebページパーサークラスを作成することはできませんか?
Jon Winstanley

24
ジョン、彼らは持っている。Perlには、多くのHTML :: Parser、HTML :: TreeBuilderなどがあります。言語に対応するものはほぼ確実にあります。
Chas。オーエンス

12
最良の答えは、stackoverflow.com / a / 1732454/135078(Zalgoに注意)
Kelly S. French、

3
[正規表現を使用して[X] HTMLを解析できない] [1] [1]ができない理由については、十分な説明があります。stackoverflow.com/ a / 1732454/468725
Pavel P

4
ここでは、パターンを使用してHTMLを確実に解析できる方法と、そうしたくない理由を説明します。
tchrist

回答:


260

ここにあなたのためのいくつかの楽しい有効な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/>

6
XMLのもの?そこにはいくつかの異なる構造がありますが、それは面倒ですか?DTD内部サブセット?それが新しい&entityを定義しています。「y」と呼ばれ、通常、引用符で囲まれていない場合、内部サブセットを終了する「]>」シーケンスを含みます。
ボビンス2009

16
(これは、DTD検証パーサーでなくても、ドキュメントを適切に解析するには、XMLの難解で古風なDTD機能のいくつかについてかなり深い知識が必要であることを示しています。)
bobince

17
HTMLの例では、あまり知られていない機能であるショートタグを利用しています。詳しくはw3.org/QA/2007/10/shorttags.html
netvope

25
上記のように誰かがHTMLを書くたびに、Tim Berners-Leeは涙を流します。
fgysinがモニカを復活させる'09 / 09/15

5
StackoverflowのSyntaxハイライターが「]」の最初の出現で失敗する方法が大好きです。
GlassGhost 2012年

71

実は

<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の解析に関する最大の問題は、人々が通常すべての構文規則を正しく理解していないことです。ブラウザがタグをHTMLとして解釈するということは、実際に有効なHTMLを記述したことを意味しません。

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

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

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

HTMLは、自分で解析することすら難しいです。最初に、合法的な構文には、あなたが気付かないかもしれない多くの小さな微妙な点があります。次に、実際のHTMLは巨大な悪臭の山です(私のドリフトを取得します)。タグスープのようなHTMLをうまく処理するさまざまな緩いパーサーライブラリがあります。これらを使用してください。


8
>としてエスケープする必要はありません。
ジョーイ

8
OK、s / valid / exists in the wild / g
Chas。オーエンス

1
実際、仕様に従って、エスケープする必要があるのと同じようにエスケープする必要があります。そして、属性として "as&quot;および 'as&
apos

19
仕様では、「>」はエスケープする必要があるとは述べていません。ただし、コンテンツ内のシーケンス「]]>」の特殊な場合を除きます。このため、常に「>」をエスケープするのが最も簡単ですが、仕様では必須ではありません。
ボビンス2009年

8
>記号はHTMLで完全に有効ですstackoverflow.com/questions/94528/...
JFS

56

私はこの件についてブログ全体を書きました:正規表現の制限

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

前の段落には少し注意が必要です。特定の正規表現の実装で、再帰の考え方がサポートされるようになりました。ただし、正規表現に再帰を追加し始めると、実際には境界が拡張され、パーサーを検討する必要があります。


20

リストにない1つの問題は、属性が任意の順序で表示される可能性があることです。そのため、正規表現がhref "foo"とクラス "bar"のリンクを探している場合、それらは任意の順序で来ることができ、その他の任意の数を持つことができます。それらの間のもの。


ああ、はい、それは私にこれを尋ねるように促した質問でさえありました(最初のリンク)。
Chas。オーエンス

16

それはあなたが「解析」によって何を意味するかによる。一般的に言えば、XML文法は決して規則的ではないため、正規表現を使用してXMLを解析することはできません。簡単に言うと、正規表現は数えられないので(まあ、Perl正規表現は実際に数えることができるかもしれません)、開閉タグのバランスをとることはできません。



1
@RishulMatta:どうやって?後方参照の数は限られているため、タグを逆にする必要があることに注意してください...さらに、正規表現の厳密な定義では後方参照が許可されていません。
Willem Van Onsem

.NETは、ポップとプッシュを行う式のバランスをとることができ、理論的には階層の照合に使用できます。しかし、それはまだ悪い考えです。
アベル、

9

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

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

ただし、要件がhtml / xmlの解析ではなく、html / xmlの「既知の良好な」ビットで1つの小さなデータを取得することである場合は、正規表現またはさらに単純な「サブストリング」でも十分です。


7
「十分」を定義します。必然的に、単純な正規表現は機能しません。一致していない、または一致していないのはバグではありませんか?その場合、正規表現の使用は間違いです。HTMLとXMLのパーサーは使いにくいものではありません。それらを学ぶことを避けることは偽の経済です。
Chas。オーエンス

1
わかりました、「十分に良い」と定義してください。クライアントのIPアドレスを通知するWebページがあるとします。それだけです。次に、IPアドレスを通知するクライアントマシン用のアプリケーションを作成する必要があります。私はそのサイトに行き、IPアドレスを探してそれを返します。HTMLの解析は必要ありません。
ロビン・デイ

2
形式が完全に制御されている任意の文字列がある場合、文字列がたまたま整形式のXMLであるという事実は、実際には関係ありません。しかし、XMLのユースケースは実際にはほとんどこのカテゴリに分類されません。
Robert Rossney 2009年

15
辛い経験から、たいていの場合、不条理な複雑な正規表現パターンを使用して、必要なものを取得することが可能であることがわかります。Webサイトが陽気な小さな変更を受けるまで、この正規表現をスローして、ウィンドウの外で2日間泣いて、新たに始めることができます。
Thomasz 2009

@ロバート:「ほとんどユースケースはない」は誇張です。私の経験では、一般的に十分なユースケースがあります。YAGNIがここに適用されます...時々。トリックは、あなたが対処している特定のタスクのために、あなたのソリューションがどのように防弾で長寿命である必要があるかを知ることです。ロビンには良い点があります。彼が言っているのは、完全なXML解析は常に価値があるとは限らないということです...それを使用する方法を知っていても、それは真実です。
LarsH 2011

6

通常、人々はデフォルトで貪欲なパターンを書くことになり、多くの場合、考えられない。*でファイルの大きなチャンクを可能な最大の<foo>。* </ foo>に丸呑みにします。


2
繰り返しをで遅延させるのと同様に、の.*?<ような否定された文字クラスを使用することで修正できます[^<]*<。(免責事項:明らかにそれはまだ間違いのないことではありません。それが問題のポイントです。)
Rory O'Kane

6

「車輪を再発明しないでください」と言いたくなります。ただし、XMLは本当に複雑な形式です。だから多分私は「シンクロトロンを再発明しないでください」と言うべきです。

おそらく正しい決まり文句は、「ハンマーさえあれば...」から始まります。正規表現の使い方を知っているので、正規表現は解析に長けているので、なぜXML解析ライブラリを学ぶ必要があるのでしょうか。

XMLの解析は 難しいからです。XML構文解析ライブラリの使用方法を学ぶ必要がないことで節約できる作業は、創造的な作業とバグのやり直しで補う以上のものになります。あなた自身のために、グーグル「XMLライブラリ」と他の誰かの仕事を活用してください。


3
C ++ほど複雑ではありません。
Cole Johnson

6
@Cole "Cole9" Johnson C ++の解析にもREを使用しません。
Isaac Rabinovitch 2013

2
XMLがシンクロトロンである場合、C ++はラージハドロンコライダーになります。
Kevin Kostlan、2015

4

私は信じている 、この 古典はあなたが探している情報を持っています。あなたはそこのコメントの1つで要点を見つけることができます:

ここでの欠点は、HTMLがチョムスキータイプ2文法(文脈自由文法)であり、RegExがチョムスキータイプ3文法(正規表現)であることです。タイプ2の文法はタイプ3の文法よりも根本的に複雑であるため、これを機能させることはできません。しかし、多くは試み、成功を主張する人もいれば、失敗を見つけて完全に失敗する人もいます。

ウィキペディアからのより多くの情報:Chomsky Hierarchy


6
「正規表現」は、正式な文法の議論では、こことまったく同じ意味を持ちません。ほとんどの現存する正規表現エンジンは、チョムスキータイプ3文法よりも強力です(貪欲でないマッチング、後方参照など)。一部の正規表現エンジン(Perlなど)は完全なチューリングです。これらもHTMLを解析するための貧弱なツールであることは事実ですが、この頻繁に引用される議論が理由ではありません。
dubiousjim

4

問題は次のように要約されます。

  1. 正規表現はほぼ常に正しくありません。正しく一致しなくなる正当な入力があります。十分に努力すれば、99%正確、つまり99.999%にすることができますが、100%正確にすることは、XMLがエンティティを使用することで許容する奇妙なことのために、ほとんど不可能です。

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

  3. 正規表現が99.99%のケースをカバーするのに十分に正確である場合、それは完全に読み取り不可能で、保守不可能になります。

  4. 中程度のサイズの入力ファイルでは、正規表現のパフォーマンスが非常に悪くなる可能性が非常に高くなります。XMLとの最初の出会いは、着信したXMLドキュメントを(誤って)解析するPerlスクリプトを適切なXMLパーサーに置き換えることでした。300行の読み取り不可能なコードを誰でも理解できる100行に置き換えただけでなく、ユーザーの応答時間を改善しました10秒から約0.1秒まで。


1

一般的に言えば、XML文法は決して規則的ではないため、正規表現を使用してXMLを解析することはできません。簡単に言うと、正規表現は数えられないので(まあ、Perl正規表現は実際に数えることができるかもしれません)、開閉タグのバランスをとることはできません。

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

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


まず、再帰的な正規表現は正規表現ではありません(括弧内を見ると、Perlの再帰的な正規表現がHTMLの処理に必要なものを数えることができることがわかります)。次に、あなたの例は、整形式のXHTMLまたはXMLの場合です。HTMLは整形式ではありません。第3に、再帰正規表現言語または汎用プログラミング言語で記述されたパーサーを拡張および維持する方が簡単かどうかを自問する必要があります。
Chas。オーエンス

第四に、あなたの例でさえ、まだ有効なXMLでありながら、些細なことです。content_blockとidの間にスペースを1つ追加すると失敗します。あと数分費やしても、コードに他の構造上のエラーが見つかることは間違いありません。それは良い考えではありません。
Chas。オーエンズ

1

ここで、この問題に対する簡単な答えを示しました。100%のマークは考慮されていませんが、前処理作業を行う場合にどのように可能かを説明します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.