tag - 正規表現でXMLとHTMLを解析することが難しい理由の例をいくつか挙げることができますか?




regular expression remove html tags (8)

over何度何度何度何度何度何度何度何度何度もXMLやHTMLを正規表現で解析しようとしています。 XMLとHTMLの解析が難しい理由のいくつかを以下に示します。

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

<tag
attr="5"
/>

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

<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>

あなたが知っている他の邪魔者は何ですか?


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

同意しません。 正規表現で再帰的に使用する場合は、開いているタグと閉じるタグを簡単に見つけることができます。

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


あなたのために有効な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>

すべてのブラウザ固有の無効な構文解析については言及しません。

それに対する幸運のピッチング正規表現!

EDIT(JörgW Mittag):これは、整形式で有効なHTML 4.01の別の素敵な部分です:

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

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


人々は実際には正規表現を使って実際にミスを犯しているのですか、それとも達成しようとしている作業には十分なのですか?

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

しかし、あなたの要件がhtml / xmlを解析するのではなく、ちょうどhtml / xmlの "既知の良い"ビットのデータの小さなビットを取得するのであれば、正規表現やさらに単純な "部分文字列"で十分です。


実際に

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

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

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

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"
/>

そしてもう一つの楽しい方法があります:あなたの属性引用文字として "or"

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

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

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

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

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

HTMLはあまりにも難しいので、自分で解析することはできません。 最初に、法的な構文には気づかないかもしれない小さな微妙な要素があります。第2に、野生のHTMLは巨大な悪臭を帯びています。 タグスープのようなHTMLを扱う際にはうってつけの、さまざまなラックスパーサーライブラリがあります。これらを使うだけです。


私は "車輪を再発明しないでください"と言ってしまいます。 XMLは本当に複雑な形式です。 だから、 "シンクロトロンを再発明しないでください"と言わなければならないかもしれません。

おそらく、正しいクリシェは「あなたが持っているものはすべてハンマーです」ということです。正規表現の使い方を知っていれば、正規表現は構文解析がうまくいくので、XMLパースライブラリを覚えるのはなぜですか?

XMLの解析は難しいためです 。 XML解析ライブラリを使用することを習得する必要がないために手間をかけずに済むことは、創造的な作業とバグのスワッティングによって補うことができます。 あなた自身のために、Googleの "XMLライブラリ"と他の人の仕事を活用してください。


私はhereこの問題に対する簡単な答えを出しました。 それは100%を占めるわけではありませんが、前処理をしたい場合はどうすればいいのか説明します。


私はこのテーマに関するブログエントリ全体を書いた: 正規表現の限界

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

前の段落にはわずかな注意が必要です。 ある種のregexの実装は、再帰の考え方をサポートするようになりました。 しかし、いったん正規表現に再帰を追加し始めると、本当に境界が広がっているので、パーサーを考慮する必要があります。





regex