RegExは、XHTML自己完結型タグを除くオープンタグと一致します


1474

これらのすべての開始タグを一致させる必要があります。

<p>
<a href="foo">

しかし、これらではありません:

<br />
<hr class="foo" />

私はこれを思いつき、それが正しいことを確認したかったのです。キャプチャしてa-zいるだけです。

<([a-z]+) *[^/]*?>

私はそれが言うと信じています:

  • 次より小さい
  • azを1回以上検索(およびキャプチャ)してから、
  • ゼロ個以上のスペースを見つけて、
  • 0回以上は、貪欲以外の任意の文字を検索し/、その後、
  • より大きいを見つける

その権利はありますか?そしてさらに重要なことに、あなたはどう思いますか?

回答:


4417

正規表現では[X] HTMLを解析できません。正規表現ではHTMLを解析できないからです。正規表現は、HTMLを正しく解析するために使用できるツールではありません。ここで何度もHTMLと正規表現の質問に回答したので、正規表現を使用するとHTMLを使用できなくなります。正規表現は、HTMLで採用されている構造を理解するには不十分で高度なツールです。HTMLは通常の言語ではないため、正規表現で解析できません。正規表現クエリは、HTMLを意味のある部分に分解する機能を備えていません。何度もですが、私には届きません。Perlで使用されている強化された不規則な正規表現でさえ、HTMLを解析するタスクに対応できません。あなたは決して私をクラックさせません。HTMLは、正規表現で解析できないほど複雑な言語です。Jon Skeetでさえ、正規表現を使用してHTMLを解析することはできません。正規表現を使用してHTMLを解析しようとするたびに、不浄な子が処女の血を流し、ロシアのハッカーがWebアプリケーションを作成します。正規表現でHTMLを解析すると、汚染された魂が生活の領域に呼び出されます。HTMLと正規表現は、愛、結婚、儀式の幼児殺害のように一緒に使用されます。<center>はそれを保持できません。正規表現とHTMLが同じ概念空間で一緒に働く力は、水っぽいパテのようにあなたの心を破壊します。正規表現を使用してHTMLを解析する場合、それらにそれらを与えると、その基本的な多言語プレーンで名前を表現できないもののために非人道的な苦労に私たち全員を運命づける彼らの冒涜的な方法、彼は来る。HTML-plus-regexpは、あなたが観察している間、感覚の神経を液化させ、あなたの精神は恐怖の猛攻撃で衰退します。遅すぎる遅すぎる保存できない子どもの奇妙な表現が正規表現がすべての生きた組織を消費することを保証します(以前に予言されたように、HTMLを除く)親愛なる主は、正規表現を使用してこの惨事生き残ることができますHTMLは恐怖の拷問やセキュリティホールを永遠に人類を運命づけられたREGEの使用プロセスのHTMLへのツールとしてのxをブレア確立し、この世界とCHと腐敗したエンティティの恐怖レルム(SGML実体のような、しかし、より多くの壊れた)をglimp単なる SEのをREGの世界HTMLのためのexパーサはイン意志 tantly輸送のAP rogrammerの意識が私 NTO AW ORL叫ん不断のD、彼が来ます、pestilent SL ithy正規表現感染WIL あなたHT食い入るリットルのすべての時間のためのMLパーサ、アプリケーションと存在Visual Basicが唯一の悪いことのように彼は彼コム来る ES 致しませんFiの GHT時間Eくる、HIの不道徳な輝きデstro҉yingすべての啓発、HTMLタグが漏れるfr̶ǫmYO URの目のようなLIQ UIDのp AIN、再定期EXPの歌ssionの解析が extiますMORのnguish声SPからTAL男を、私はそれはあなたが見ることができる見ることができ、ここでそれは美しいトンである彼は、F inal snufFING O F嘘の男ALL IS LOST Aの LL I SL第OST eは、彼が来るポニー彼は、COMのを、彼は共同ES のトンを、彼 ICHまたはpermeat ESアルリットルMY FAC E MY FACEᵒh神のn O NO NOO O ON Θストップトン彼*̶͑̾̾GL ES ͎a̧͈͖r̽̾̈́͒͑eN OTを本当のZA̡͊͠͝LGΌISͮ҉̯͈͕̹̘T O͇̹̺Ɲ̴ȳ̳TH E PO NYH̸̡̪̯ͨ͊̽̅̾Ȩ̶̧̨̬̩̹̭̯̾͛ͪ̈ͧ̾ͬ͘C̷̙̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝ S


代わりにXMLパーサーを使用してみましたか?


モデレーターのメモ

この投稿は、コンテンツへの不適切な編集を防ぐためにロックされています。投稿は見た目とまったく同じように見えます-その内容に問題はありません。注意のためにフラグを立てないでください。


179
コビ:アシスタントの「正規表現オフィサーでHTMLを解析しない」の投稿をやめるときがきたと思います。何度言っても、毎日来るのを止めることはありません。それは失われた原因であり、他の誰かが少し戦うことができます。だから、もし必要なら、正規表現でHTMLを解析してください。これは壊れたコードであり、生と死ではありません。
ボビンス2009年

27
RegExを使用してこの回答を解析することは可能ですか?
Chris Porter、

2
この投稿が表示されない場合は、栄光の中でのスクリーンキャプチャを以下に示し
Andrew

3251

一方で、任意の HTMLのみ正規表現は不可能であると、時には解析するためにそれらを使用するために、適切なだ限られ、知られている HTMLのセットを。

データをスクレイピングしてからデータベースに挿入するHTMLページの小さなセットがある場合、正規表現は正常に機能する可能性があります。たとえば、最近、私は議会のWebサイトから取得したオーストラリア連邦代表の名前、政党、および地区を取得したいと考えていました。これは限られた1回限りの仕事でした。

Regexesは私には問題なく動作し、セットアップも非常に高速でした。


131
また、大規模なドキュメントからかなり定期的にフォーマットされたデータをスクレイピングすることは、一般的なパーサーよりもスキャンと正規表現を慎重に使用することで、はるかに速くなります。また、正規表現のコーディングに慣れている場合は、xpathのコーディングよりもはるかに高速にコーディングできます。そして、ほぼ確実に、あなたがスクレイピングしているものの変化に対して脆弱ではありません。だからブレ。
マイケルジョンストン

255
@MichaelJohnston「壊れやすい」?ほとんど間違いなくそうではありません。正規表現は、XMLパーサーが暗黙的に無視できるよりも、テキスト形式の詳細を考慮します。&foo;エンコーディングとCDATAセクションの切り替え?HTML縮小機能を使用して、ブラウザーがレンダリングしないドキュメント内のすべての空白を削除しますか?XMLパーサーは気にせず、適切に記述されたXPathステートメントも気にしません。一方で、正規表現ベースの「パーサー」...
Charles Duffy

41
@CharlesDuffyは、1回限りのジョブでは問題ありません。スペースには\ s +を使用します
量子

68
@xiaomao確かに、残りの時間「失敗する」に失敗する80%の解決策を得るためにすべての落とし穴と回避策を知る必要がある場合、私はあなたを止めることはできません。その間、構文的に有効なXMLを100%処理するパーサーを使用して、フェンスのそばにいます。
Charles Duffy

374
私はかつて、すべて同じHTMLテンプレートを使用して、1万ページからいくつかのデータを取得する必要がありました。それらはパーサーを窒息させるHTMLエラーで散らかされており、それらのすべてのスタイリングはインラインまたは<font>等でした:DOMをナビゲートするのに役立つクラスまたはIDはありません。「正しい」アプローチで1日戦った後、私はようやく正規表現ソリューションに切り替え、1時間で動作しました。
Paul A Jungwirth、2012

2039

ここでの欠点は、HTMLがチョムスキータイプ2文法(文脈自由文法)であり、RegExがチョムスキータイプ3文法(標準文法)であることです。タイプ2の文法はタイプ3の文法よりも根本的に複雑であるため(チョムスキー階層を参照)、RegExでXMLを解析することは数学的に不可能です。

しかし、多くの人は試してみますが、中には成功を主張する人もいますが、他の人が間違いを見つけて完全に混乱させるまでは。


226
OPは、XHTMLの非常に限定されたサブセット、つまり開始タグの解析を求めています。(X)HTMLをCFGにするのは、(文法規則のようにA -> s A e)他の要素の開始タグと終了タグの間に要素がある可能性です。(X)HTMLの開始タグ内にこのプロパティはありませ。開始タグに他の開始タグを含めることはできません。OPが解析しようとしているサブセットはCFGではありません。
LarsH

101
CS理論では、正規言語文脈自由言語の厳密なサブセットですが、主流のプログラミング言語での正規表現の実装はより強力です。以下のようnoulakaz.net/weblog/2007/03/18/...は説明し、いわゆる「正規表現は、」確かにCS理論からの正規表現が達成できないことを何かである、単項で素数かどうかを確認することができます。
アダムミハルシン2012年

11
@eyelidlessness:同じ「のみ」がすべてのCFGに適用されますか?つまり、(X)HTML入力が整形式でない場合、本格的なXMLパーサーでさえ確実に機能しません。おそらく、あなたが参照している「(X)HTML構文エラーが実際のユーザーエージェントに実装されている」の例を挙げれば、私はあなたが何をより良くしているのか理解できます。
LarsH

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

27
これは、ここで最も「完全かつ短い」答えです。それは人々が正式な文法と言語の基礎を学び、うまくいけばいくつかの数学を学ぶように導くので、多項式時間でNPタスクを解くような希望のないことに時間を費やさないでしょう
mishmashru

1332

これらの人に耳を傾けないでください。タスクを細かく分割すると、完全に正規表現を使用してコンテキストフリーの文法を解析できます。これらを順番に実行するスクリプトを使用して、正しいパターンを生成できます。

  1. 停止問題を解決します。
  2. 円を直角にします。
  3. O(log n)以下で巡回セールスマン問題を解きます。それ以上の場合は、RAMが不足し、エンジンがハングします。
  4. パターンはかなり大きくなるので、ランダムデータを可逆圧縮するアルゴリズムがあることを確認してください。
  5. あと少しで、全部をゼロで割ります。かんたん。

私は最後の部分を自分で完成させたわけではありませんが、近づいていることはわかっています。投げ続けますCthulhuRlyehWgahnaglFhtagnException何らかの理由でsをので、VB 6に移植して使用しますOn Error Resume Next。壁に開いたばかりのこの奇妙なドアを調査したら、コードを更新します。うーん。

PS Pierre de Fermatもその方法を理解しましたが、彼が書いていたマージンはコードに対して十分な大きさではありませんでした。


80
ゼロによる除算は、あなたが言及する他の問題よりもはるかに簡単な問題です。単純な浮動小数点演算(誰もがそうすべきだが誰もそうではない)ではなく、間隔を使用する場合、何かを[間隔を含む]ゼロで幸せに除算できます。結果は、単にプラスとマイナスの無限大を含む間隔になります。
rjmunro

148
フェルマーの小さなマージンの問題は、最新のテキスト編集ソフトウェアのソフトマージンによって解決されました。
kd4ttc 2013年

50
フェルマートの小さなマージンの問題は、フォントサイズ
heltonbiker

29
参考までに:フェルマーの問題は1995年に実際に解決され、数学者は358年しかかかりませんでした。
jmiserez 2015年

10
常温核融合から得られたブラウンラチェットを使用することで、この粘着性のあるゼロ除算ステップをバイパスすることができました。ただし、宇宙定数を削除した場合にのみ機能します。
Tim Lehner、2016年

1073

免責事項:オプションがある場合は、パーサーを使用してください。それは言った...

これは、HTMLタグの照合に使用する正規表現(!)です。

<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>

完璧ではないかもしれませんが、私はこのコードを多くのHTMLで実行しました。それは次のような奇妙なものもキャッチすることに注意してください<a name="badgenerator"">Webに表示されるの。

自己完結型のタグと一致しないようにするには、Kobiの否定的な後読みを使用することもできます。

<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+(?<!/\s*)>

または、そうでない場合は単に組み合わせる。

反対投票者へ:これは実際の製品からの作業コードです。このページを読んでいる人が、HTMLで正規表現を使用することは社会的に受け入れられるという印象を受けるとは思えません。

警告:この正規表現は、CDATAブロック、コメント、スクリプトおよびスタイル要素が存在する場合でも機能しないことに注意してください。良いニュースは、正規表現を使用してそれらを取り除くことができるということです...


95
私は、普遍的に完璧ではないということについて、泣くよりも
健全

55
誰かがHTML内でCDATAを使用していますか?
ダニューブセーラー2013

16
そのため、実際には正規表現だけで解析の問題を解決するのではなく、パーサーの一部としてこれが機能する場合があります。PS:機能する製品は良いコードを意味するものではありません。違反はありませんが、これは産業用プログラミングが機能し、お金を稼ぐ方法です
mishmashru

32
正規表現の開始は、非常に短い有効なHTMLで失敗します<!doctype html><title><</title>。シンプルながら'<!doctype html><title><</title>'.match(/<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/g)戻ります。["<!doctype html>", "<title>", "<</title>"]["<title>", "</title>"]

2
与えられた例と一致させようとし、一致させようとしない場合、/ <。([^ r>] [^>] *)?> / gは機能します:-) // javascript: '<p> <a href = "foo"という> <br /> <hrでクラス= "foo"という/>'.match(/<.([^r>][^>]*)?>/g)
淫魔

506

地球が丸い(またはおそらく奇妙な言葉を使いたければ地球は扁平な回転楕円体である)とあなたに告げる人々がいます。彼らは嘘をついている。

正規表現は再帰的であってはならないことを教えてくれる人がいます。彼らはあなたを制限しています。彼らはあなたを征服する必要があり、彼らはあなたを無知に保つことによってそれを行います。

あなたは彼らの現実の中で生きるか、赤い錠剤を飲むことができます。

Lord Marshalと同様に(彼はMarshal .NETクラスの親類ですか?)、Underverse Stack Based Regex-Verseを見て、想像もできないような力の知識で戻ってきました。はい、彼らを守るオールドワンか2人がいたと思いますが、彼らはテレビでフットボールを見ていましたので、難しくありませんでした。

XMLのケースは非常に単純だと思います。(.NET構文の)RegExは、base64でデフレートおよびコード化されて、弱い心で理解しやすくするために、次のようになります。

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
+r/vD34mUADO1P4/AQAA//8=

設定するオプションはRegexOptions.ExplicitCaptureです。あなたが探しているキャプチャグループはELEMENTNAMEです。キャプチャグループERRORが空でない場合、解析エラーが発生し、正規表現が停止しました。

人間が読める形式の正規表現に再変換するときに問題が発生した場合は、次のようにしてください。

static string FromBase64(string str)
{
    byte[] byteArray = Convert.FromBase64String(str);

    using (var msIn = new MemoryStream(byteArray))
    using (var msOut = new MemoryStream()) {
        using (var ds = new DeflateStream(msIn, CompressionMode.Decompress)) {
            ds.CopyTo(msOut);
        }

        return Encoding.UTF8.GetString(msOut.ToArray());
    }
}

わからない場合は、いいえ、冗談ではありません(しかし、私はうそをついています)。それが動作します。私はそれをテストするためにたくさんの単体テストを構築しました、そして私は適合テスト(の一部)さえ使用しました。これはトークナイザーであり、本格的なパーサーではないため、XMLをコンポーネントトークンに分割するだけです。DTDを解析/統合しません。

ああ...あなたが正規表現のソースコードが必要な場合、いくつかの補助的な方法があります:

xmlまたは完全な正規表現をトークン化する正規表現


68
良い主よ、それは巨大です。私の最大の質問はなぜですか?最近のすべての言語にXMLパーサーがあることに気づきましたか?これらすべてを3行で行うことができ、確実に機能します。さらに、純粋な正規表現は特定のことを実行できないことが証明されていることにも気づいていますか?ハイブリッド正規表現/命令コードパーサーを作成していない場合は、実際のパーサーとは異なります。ランダムデータも圧縮できますか?
Justin Morgan

113
@ジャスティン私は理由を必要としません。それは可能だった(そしてそれは違法/不道徳ではなかった)ので、私はそれを行った。私たちが認めているものを除いて、心に制限はありません(ナポレオンヒル)...現代の言語はXMLを解析できますか?本当に?そしてそれは違法だと思いました!:-)
xanatos

76
サー、私は確信しています。このコードを永久運動マシンのカーネルの一部として使用します。特許庁の愚か者が私の申請を拒否し続けていると信じられますか?さて、それらを紹介します。全部見せます!
Justin Morgan、

31
@ジャスティンだから、正規表現はそうではありませんが、Xmlパーサーは本質的にバグフリーです?Xmlパーサーに定義上バグがないわけではないため、XMLがクラッシュする可能性があり、ステップ0に戻ります。次のように言います。Xmlパーサーとこの正規表現の両方が、すべての「合法的な"XML。彼らは「違法」なXMLを解析できます。バグはそれらの両方をクラッシュさせる可能性があります。C#XmlReaderは、この正規表現よりも確実にテストされています。
xanatos

31
いいえ、バグのないものはありません:1)すべてのプログラムには少なくとも1つのバグが含まれています。2)すべてのプログラムには、少なくとも1行の不要なソースコードが含まれています。3)#1と#2を使用し、論理帰納法を使用することで、すべてのプログラムをバグのある1行のコードに削減できることを証明するのは簡単です。(Learning Perlから)
Scott Weaver

299

シェルでは、sedを使用してHTMLを解析できます

  1. Turing.sed
  2. HTMLパーサーを書く(宿題)
  3. ???
  4. 利益!

関連(なぜ正規表現一致を使用すべきではないのか):


3
@kenorbさん、冗談は聞き取れませんでした。質問と回答をもう一度読んでください。これは、一般的なHTML解析ツールや、HTML解析シェルツールではなく、正規表現によるHTMLの解析です。
Palec、2015年

1
いいえ、@ Abdul。それは完全に、証明できます(数学的な意味では)不可能です。
Palec 2017年

3
はい、その回答はそれをうまく要約しています、@ Abdul。ただし、正規表現の実装は実際には定期的ではないことに注意してください、数学的な意味で表現でこれらは、より強力な、多くの場合チューリング完全な(タイプ0文法に相当)構成を持っています。議論はこの事実に反しますが、しかし正規表現がそのような仕事をすることができるように決して意図されていなかったという意味でまだいくぶん有効です。
Palec 2017年

2
ちなみに、私が言及した冗談は、kenorbの(根本的な)編集、特にリビジョン4、@ Abdulの前のこの回答の内容でした。
パレック

3
おかしなことは、OPが正規表現を使用してHTMLを解析するように要求しなかったことです。彼は正規表現を使用してテキスト(たまたまHTML)を照合するように求めました。これは完全に合理的です。
Paralife

274

XML、特にHTMLを解析するための適切なツールに同意しますはパーサーであり、正規表現エンジンではない。ただし、他の人が指摘したように、正規表現を使用する方が速くて簡単で、データ形式がわかっている場合は作業が完了することがあります。

マイクロソフトには、実際には.NET Frameworkの正規表現のベストプラクティスのセクションがあり、特に入力ソースの検討について説明しています。

正規表現には制限がありますが、次のことを考慮しましたか?

.NETフレームワークは、正規表現に関しては、バランスグループ定義をサポートするという点で独特です。

このため、正規表現を使用してXMLを解析できると思います。ただし、有効なXMLなければならないことに注意してください(ブラウザーはHTMLを非常に許容し、HTML内での不正なXML構文を許可します)。これは、「バランスグループの定義」により、正規表現エンジンがPDAとして機能できるようになるためです。

上記の記事1からの引用:

.NET正規表現エンジン

上記のように、適切にバランスの取れた構造は正規表現では記述できません。ただし、.NET正規表現エンジンは、バランスのとれた構成を認識できるようにするいくつかの構成を提供します。

  • (?<group>) -キャプチャした結果をグループという名前でキャプチャスタックにプッシュします。
  • (?<-group>) -キャプチャスタックから、名前グループを含む最上位のキャプチャをポップします。
  • (?(group)yes|no) -groupという名前のグループが存在する場合は、yes部分に一致します。それ以外の場合は、どの部分にも一致しません。

これらの構成体を使用すると、プッシュ、ポップ、空のスタック操作の単純なバージョンを基本的に許可することで、.NET正規表現で制限付きPDAをエミュレートできます。単純な操作は、インクリメント、デクリメント、およびゼロとの比較にそれぞれ相当します。これにより、.NET正規表現エンジンはコンテキストフリー言語のサブセット、特に単純なカウンターのみを必要とするものを認識することができます。これにより、従来とは異なる.NET正規表現で、適切にバランスのとれた個々の構成を認識することができます。

次の正規表現について考えてみます。

(?=<ul\s+id="matchMe"\s+type="square"\s*>)
(?>
   <!-- .*? -->                  |
   <[^>]*/>                      |
   (?<opentag><(?!/)[^>]*[^/]>)  |
   (?<-opentag></[^>]*[^/]>)     |
   [^<>]*
)*
(?(opentag)(?!))

フラグを使用します。

  • 単線
  • IgnorePatternWhitespace(正規表現を縮小してすべての空白を削除する場合は不要)
  • IgnoreCase(不要)

正規表現の説明(インライン)

(?=<ul\s+id="matchMe"\s+type="square"\s*>) # match start with <ul id="matchMe"...
(?>                                        # atomic group / don't backtrack (faster)
   <!-- .*? -->                 |          # match xml / html comment
   <[^>]*/>                     |          # self closing tag
   (?<opentag><(?!/)[^>]*[^/]>) |          # push opening xml tag
   (?<-opentag></[^>]*[^/]>)    |          # pop closing xml tag
   [^<>]*                                  # something between tags
)*                                         # match as many xml tags as possible
(?(opentag)(?!))                           # ensure no 'opentag' groups are on stack

A Better .NET正規表現テスターでこれを試すことができます

私は次のサンプルソースを使用しました:

<html>
<body>
<div>
   <br />
   <ul id="matchMe" type="square">
      <li>stuff...</li>
      <li>more stuff</li>
      <li>
          <div>
               <span>still more</span>
               <ul>
                    <li>Another &gt;ul&lt;, oh my!</li>
                    <li>...</li>
               </ul>
          </div>
      </li>
   </ul>
</div>
</body>
</html>

これは一致を見つけました:

   <ul id="matchMe" type="square">
      <li>stuff...</li>
      <li>more stuff</li>
      <li>
          <div>
               <span>still more</span>
               <ul>
                    <li>Another &gt;ul&lt;, oh my!</li>
                    <li>...</li>
               </ul>
          </div>
      </li>
   </ul>

実際には次のように出てきましたが:

<ul id="matchMe" type="square">           <li>stuff...</li>           <li>more stuff</li>           <li>               <div>                    <span>still more</span>                    <ul>                         <li>Another &gt;ul&lt;, oh my!</li>                         <li>...</li>                    </ul>               </div>           </li>        </ul>

最後に、Jeff Atwoodの記事「Parsing Html The Cthulhu Way」を本当に楽しんだ 。面白いことに、この質問への回答は現在4千票を超えています。


18
System.TextC#の一部ではありません。.NETの一部です。
ジョンサンダース

8
あなたの正規表現の最初の行(に(?=<ul\s*id="matchMe"\s*type="square"\s*>) # match start with <ul id="matchMe"...)、「<UL」と「ID」の間にあるべき\s+ではない\s*)。あなたはそれが<ULID = ...と一致する場合を除き、
C0deH4cker

@ C0deH4cker正解\s+です\s*。式はの代わりに持つ必要があります。
サム

4
私はそれを本当に理解しているわけではありませんが、あなたの正規表現は失敗すると思います<img src="images/pic.jpg" />
Scheintod '27

3
@Scheintodコメントありがとうございます。コードを更新しました。前の式/は、<img src="images/pic.jpg" />html で失敗した内部のどこかにある自己終了タグで失敗しました。
2013

258

PHPでXMLとHTMLを解析するには、QueryPathを使用することを勧めします。基本的にはjQueryとほぼ同じ構文ですが、サーバー側のみです。


8
@Kyle-jQueryはXMLを解析せず、クライアントの組み込みパーサー(存在する場合)を使用します。したがって、jQueryを使用する必要はありませんが、わずか2行の古いJavaScriptで済みます。組み込みのパーサーがない場合、jQueryは役に立ちません。
RobG 2013年

1
@RobG実際、jQueryは組み込みのパーサーではなくDOMを使用します。
Qix-モニカは2014

11
@ Qix—ドキュメントの作成者には、「jQuery.parseXMLはブラウザのネイティブ解析機能を使用する…」と伝えた方がよいでしょう。ソース:jQuery.parseXML()
RobG

6
ミームの質問(meta.stackexchange.com/questions/19478/the-many-memes-of-meta/…)からここに来て、答えの1つは「jQueryを使用する」
Jorn

221

正規表現でHTMLを解析できないという答えは正しいですが、ここでは当てはまりません。OPは、正規表現を使用して1つのHTMLタグを解析したいだけであり、これは正規表現で実行できるものです。

しかし、提案された正規表現は間違っています:

<([a-z]+) *[^/]*?>

正規表現に何かを追加した場合、バックトラックにより<a >>、のようなばかげたものに一致させることができますが、[^/]許容範囲が広すぎます。<space>*[^/]*[^/]*スペースにも一致する可能性があるため、冗長であることにも注意してください。

私の提案は

<([a-z]+)[^>]*(?<!/)>

どこ (?<! ... )(Perl正規表現では)否定的な後読みはありますか。これは、「<、次に単語、>以外のもの、最後が/でない可能性があり、>が続く」と読みます。

これは<a/ >(元の正規表現と同じように)のようなものを許可するため、より制限的なものが必要な場合は、スペースで区切られた属性ペアに一致する正規表現を作成する必要があります。


29
+1は、完全な(X)HTMLを解析することについてではなく、(X)HTMLのオープンタグを照合することについてです。
LarsH 2012

10
他のほとんどの答えは無視しているようですが、HTMLパーサーはHTMLの一部の実装で正規表現を非常にうまく使用できるため、ほとんどのパーサーがこれを行わなかったとしたら驚きます。
Thayne

@Thayneその通りです。個々のタグを解析する場合、正規表現はジョブに適したツールです。合理的な答えを見つけるためにページの半分までスクロールしなければならないのは、とんでもないことです。受け入れられた答えは、字句解析と解析を混同するため、正しくありません。
kasperd 2015年

2
属性値に「>」または「/」文字が含まれている場合、ここでの回答は失敗します。
Martin L

これは、コメントまたはCDataセクションを含むHTMLでは正しく機能しません。引用符で囲まれた属性に>文字が含まれている場合も、正しく機能しません。OPが提案することは正規表現を使用して実行できることに同意しますが、ここで紹介するものは単純化しすぎています。
JacquesB 2017

183

試してください:

<([^\s]+)(\s[^>]*?)?(?<!/)>

それはあなたのものに似ていますが、最後>はスラッシュの後にある必要はなく、も受け入れますh1


107
<a href="foo" title="5> 3 ">エラー</a>
ガレス、

21
それは非常に真実であり、私はそれについて考えましたが、>シンボルが適切に&gt;にエスケープされていると思いました。
コビ

65
>属性値で有効です。実際、「正規のXML」シリアル化では、を使用してはなりません&gt;。(>属性値がまったく珍しいものではないことを強調する場合を除いて、これは完全に関連しているわけではありません。)
bobince 2009年

5
@Kobi:正規表現での感嘆符(最後に向かって付けたもの)はどういう意味ですか?
Marco Demaio 2011

6
@bobince:確かですか?:私は、この有効なHTMLがあまりにもあり、もう理解していない<div title="this tag is a <div></div>">hello</div>
マルコDemaio

179

古代中国の戦略家であり、将軍であり哲学者でもある孫子は、次のように述べています。

敵を知り、自分を知っていれば、1回も負けずに100勝することができると言われています。自分だけを知っていて、相手を知らない場合は、勝つか負けるかもしれません。自分も敵も知らなければ、常に自分を危険にさらすことになります。

この場合、あなたの敵はHTMLであり、あなたはあなた自身か正規表現です。あなたは不規則な正規表現を持つPerlかもしれません。HTMLを知っている。あなた自身を知っています。

HTMLの性質を説明する俳句を作成しました。

HTML has
complexity exceeding
regular language.

Perlの正規表現の性質を説明する俳句も作成しました。

The regex you seek
is defined within the phrase
<([a-zA-Z]+)(?:[^>]*[^/]*)?>

153
<?php
$selfClosing = explode(',', 'area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed');

$html = '
<p><a href="#">foo</a></p>
<hr/>
<br/>
<div>name</div>';

$dom = new DOMDocument();
$dom->loadHTML($html);
$els = $dom->getElementsByTagName('*');
foreach ( $els as $el ) {
    $nodeName = strtolower($el->nodeName);
    if ( !in_array( $nodeName, $selfClosing ) ) {
        var_dump( $nodeName );
    }
}

出力:

string(4) "html"
string(4) "body"
string(1) "p"
string(1) "a"
string(3) "div"

基本的には、自己終了する要素ノード名を定義し、HTML文字列全体をDOMライブラリーにロードし、すべての要素を取得し、ループして、自己終了していない要素をフィルターで除外して操作します。

この目的のために正規表現を使用すべきではないことは、すでにご存じだと思います。


1
実際のXHTMLを扱っている場合は、getElementsByTagNameを追加しNSて名前空間を指定します。
meder omuraliev 2009年

148

これの正確な必要性はわかりませんが、.NETも使用している場合は、Html Agility Packを使用できませんでしたか?

抜粋:

これは、「Web外」のHTMLファイルを解析できる.NETコードライブラリです。パーサーは、「実世界」の不正なHTMLに対して非常に耐性があります。


137

最初たく>が先行していません/。見て、ここでそれを行う方法の詳細については。ネガティブ後読みと呼ばれます。

ただし、その単純な実装は<bar/></foo>、この例のドキュメントでは一致します。

<foo><bar/></foo>

解決しようとしている問題についてもう少し情報を提供できますか?タグをプログラムで反復していますか?


1
はい、そうです。現在開いているすべてのタグを特定し、それを別の配列の閉じたタグと比較します。RegExは私の脳を痛めます。
ジェフ

122

W3Cは、疑似正規表現形式での解析について説明しています:
W3Cリンク

以下のためのVaRのリンクをたどりQNameSAttribute鮮明な画像を取得します。
これに基づいて、タグの除去などを処理するかなり優れた正規表現を作成できます。


5
ここで指定されているように、それは疑似正規表現形式ではなく、EBNF形式です。XML仕様、付録6
Rob G

106

PHPでこれが必要な場合:

PHPのDOM 関数は、それが適切にXMLにフォーマットされていない限り、正常に動作しません。他の人類にとって、それらの使用がどれほど優れていても。

simplehtmldomは良いですが、少しバグがあり、かなりメモリが重いです[大きなページでクラッシュします]。

私は使ったことがないquerypathをので、その有用性についてコメントすることはできません。

もう1つ試してみると、DOMParserはリソースが非常に少なくて、しばらくの間ずっと楽しく使用しています。学ぶのが簡単で強力です。

PythonとJavaの場合、同様のリンクが投稿されました。

不賛成者のために-私は、XMLパーサーが実際の使用に耐えられないことが判明したときにのみ、クラスを作成しました。宗教的な反対投票は、有用な回答が投稿されないようにするだけです。質問の観点から物事を守ってください。


95

これが解決策です:

<?php
// here's the pattern:
$pattern = '/<(\w+)(\s+(\w+)\s*\=\s*(\'|")(.*?)\\4\s*)*\s*(\/>|>)/';

// a string to parse:
$string = 'Hello, try clicking <a href="#paragraph">here</a>
    <br/>and check out.<hr />
    <h2>title</h2>
    <a name ="paragraph" rel= "I\'m an anchor"></a>
    Fine, <span title=\'highlight the "punch"\'>thanks<span>.
    <div class = "clear"></div>
    <br>';

// let's get the occurrences:
preg_match_all($pattern, $string, $matches, PREG_PATTERN_ORDER);

// print the result:
print_r($matches[0]);
?>

深くテストするために、次のような文字列の自動終了タグを入力しました。

  1. <hr />
  2. <br/>
  3. <br>

次のタグも入力しました:

  1. 1つの属性
  2. 複数の属性
  3. 値が重引用または二重引用符にバインドされている属性
  4. 区切り文字が二重引用符の場合は単一引用符を含む属性、またはその逆
  5. 「=」記号の前、その後ろ、およびその前後の両方にスペースがある「unpretty」属性。

上記の概念実証で機能しないものが見つかった場合は、コードを分析してスキルを向上させることができます。

<編集> ユーザーからの質問が自己終了タグの解析を回避することであることを忘れていました。この場合、パターンはより単純になり、次のようになります。

$pattern = '/<(\w+)(\s+(\w+)\s*\=\s*(\'|")(.*?)\\4\s*)*\s*>/';

ユーザー@ridgerunnerは、パターンが引用符で囲まれていない属性または値のない属性を許可しないことに気づきました。この場合、微調整により次のパターンが得られます。

$pattern = '/<(\w+)(\s+(\w+)(\s*\=\s*(\'|"|)(.*?)\\5\s*)?)*\s*>/';

</編集>

パターンを理解する

誰かがパターンについてもっと学びたいと思っているなら、私はいくつかの行を提供します:

  1. 最初の部分式(\ w +)はタグ名に一致します
  2. 2番目のサブ式には、属性のパターンが含まれています。それはによって構成される:
    1. 1つ以上の空白\ s +
    2. 属性の名前(\ w +)
    3. ゼロ以上の空白\ s *(可能かどうか、ここに空白を残す)
    4. 「=」記号
    5. 再び、ゼロ個以上の空白
    6. 属性値の区切り文字、単一引用符または二重引用符( '| ")。パターンでは、PHP文字列区切り文字と一致するため、単一引用符はエスケープされます。このサブ式は括弧で囲まれているため、参照できますここでも属性のクロージャを解析するため、非常に重要です。
    7. ほとんどすべてに一致する属性の値:(。*?); この特定の構文では、貪欲な一致(アスタリスクの後の疑問符)を使用して、RegExpエンジンは「先読み」に似た演算子を有効にします。
    8. ここからがおもしろい:\ 4部分は後方参照演算子です、パターンで前に定義されたサブ式を参照であり、この場合、最初の属性区切り文字である4番目のサブ式を参照している
    9. ゼロ以上の空白\ s *
    10. 属性部分式はここで終了し、アスタリスクで指定されたゼロ個以上の可能な出現の指定で。
  3. 次に、タグが ">"記号の前の空白で終了する可能性があるため、0個以上の空白が\ s *サブパターンと一致します。
  4. 一致するタグは、単純な ">"記号、またはその前のスラッシュを使用する可能なXHTMLクロージャで終了する場合があります:(/> |>)。スラッシュは、正規表現の区切り文字と一致するため、もちろんエスケープされます。

小さなヒント:このコードをよりよく分析するには、HTML特殊文字をエスケープしないので、生成されたソースコードを確認する必要があります。


12
値のない属性を持つ有効なタグ、つまり<option selected>。また、引用符で囲まれていない属性値を持つ有効なタグとは一致しません<p id=10>
ridgerunner '25

1
@ridgerunner:コメントありがとうございます。その場合、パターンは少し変更する必要があります:$ pattern = '/ <(\ w +)(\ s +(\ w +)(\ s * \ = \ s *(\' | "|)(。*?)\\ 5 \ s *)?)* \ s *> / ';私はそれをテストし、引用符で囲まれていない属性または値のない属性の場合に動作します
Emanuele Del Grande

タグ名の前のスペースはどうですか:< a href="http://wtf.org" >正当だと確信していますが、一致していません。
Floris 2013年

7
いいえ、申し訳ありませんが、タグ名の前の空白は無効です。「かなり確実」であることに加えて、異議の証拠をいくつか提供してみませんか?これは私のもので、XML 1.1を参照するw3.org/TR/xml11/#sec-starttagsです。テストを行うとW3C検証でも警告が表示されるため、HTML 4、5、およびXHTMLでも同じことがわかります。この辺りにある他の何もかもの詩人のように、質問で指定された契約ルールに従ってコードがどこで失敗するかを実証するために、私は答えに対して数百マイナスを除いて、まだインテリジェントな議論を受けませんでした。私は彼らだけを歓迎します。
Emanuele Del Grande

@ridgerunnerもちろん、あなたのコメントは賢く歓迎されました。
Emanuele Del Grande

91

HTMLドキュメントから何かをすばやく抽出する必要があるときはいつでも、Tidyを使用してそれをXMLに変換し、次にXPathまたはXSLTを使用して必要なものを取得します。あなたの場合、このようなもの:

//p/a[@href='foo']

89

以前、HTMLParserというオープンソースツールを使用していました。さまざまな方法でHTMLを解析するように設計されており、目的を十分に果たします。HTMLを異なるツリーノードとして解析でき、そのAPIを使用してノードから属性を簡単に取得できます。それをチェックして、これがあなたを助けることができるかどうか見てください。


84

正規表現を使用してHTMLを解析するのが好きです。故意に破壊されたばかHTMLを解析しようとはしません。このコードは私のメインパーサー(Perlエディション)です。

$_ = join "",<STDIN>; tr/\n\r \t/ /s; s/</\n</g; s/>/>\n/g; s/\n ?\n/\n/g;
s/^ ?\n//s; s/ $//s; print

これはhtmlsplitと呼ばれ、HTMLを行に分割し、各行に1つのタグまたはテキストのチャンクを付けます。この行は、grepsed、Perl などの他のテキストツールやスクリプトでさらに処理できます。冗談でもありません:)楽しんでください。

巨大なWebページを処理したい場合は、簡単な操作で、私はslurp-everything-first Perlスクリプトを素晴らしいストリーミングのものに変更できます。しかし、それは本当に必要ではありません。

私はこれに反対票を投じるに違いない。

HTML分割


私の期待に反して、これはいくつかの賛成票を得たので、いくつかのより良い正規表現を提案します:

/(<.*?>|[^<]+)\s*/g    # get tags and text
/(\w+)="(.*?)"/g       # get attibutes

XML / XHTMLに適しています。

わずかなバリエーションで、乱雑なHTMLに対応できます...または、最初にHTML-> XHTMLに変換します。


正規表現を書くための最良の方法は、不透明な1行やコメント付きの複数行の怪物ではなく、Lex / Yaccスタイルです。ここではまだそれをしていません。これらはほとんど必要ありません。


35
「私は故意に破壊されたばかHTMLを解析しようとしません。」あなたのコードはどのように違いを知っていますか?
ケビンパンコ

HTMLが壊れていてもいなくても問題ありません。HTMLはタグとテキストに分割されます。失敗する可能性があるのは、エスケープされていない<または>文字がテキストまたは属性に含まれている場合だけです。実際には、私の小さなHTMLスプリッターはうまく機能します。ヒューリスティックでいっぱいの巨大な怪物は必要ありません。簡単な解決策は誰もが使えるわけではありません...!
サムワトキンス

タグ、テキスト、属性を抽出するための簡単な正規表現をXML / XHTMLに追加しました。
Sam Watkins、2012年

(属性のバグ1を取得)/(\w+)="(.*?)"/は二重引用符を想定しています。単一引用符で囲まれた値は欠落します。HTMLバージョン4以前では、単純な単語の場合、引用符で囲まれていない値を使用できます。
David Andersson

(属性バグ2を取得)/(\w+)="(.*?)"/は、属性内の属性のように見えるテキストに誤って一致する場合があります<img title="Nope down='up' for aussies" src="..." />。グローバルに適用すると、通常のテキストやhtmlコメントのようなものにも一致します。
David Andersson

74

これは、不敬な正規表現を使用してHTMLを解析するPHPベースのパーサーです。このプロジェクトの作成者として、正規表現を使用してHTMLを解析することは可能ですが、効率的ではないと言えるでしょう。サーバーサイドソリューションが必要な場合(私のwp-Typography WordPressプラグインで行ったように)、これは機能します。


1
htmlawedは、HTMLを解析してフィルター処理、変換などを行う別のPHPプロジェクトです。理解できる場合は、すばらしいコードがいくつかあります。
user594694

いいえ、正規表現ではHTMLを解析できません。ただし、一部のサブセットで機能する場合があります。
mirabilos 2014

71

HTMLをBBCodeに置き換えるための素晴らしい正規表現がいくつかあります。言い分を言わないすべての人にとって、彼はHTMLを完全に解析するのではなく、それをサニタイズしようとしていることに注意してください。彼はおそらく、彼の単純な「パーサー」が理解できないタグを削除する余裕があります。

例えば:

$store =~ s/http:/http:\/\//gi;
$store =~ s/https:/https:\/\//gi;
$baseurl = $store;

if (!$query->param("ascii")) {
    $html =~ s/\s\s+/\n/gi;
    $html =~ s/<pre(.*?)>(.*?)<\/pre>/\[code]$2\[\/code]/sgmi;
}

$html =~ s/\n//gi;
$html =~ s/\r\r//gi;
$html =~ s/$baseurl//gi;
$html =~ s/<h[1-7](.*?)>(.*?)<\/h[1-7]>/\n\[b]$2\[\/b]\n/sgmi;
$html =~ s/<p>/\n\n/gi;
$html =~ s/<br(.*?)>/\n/gi;
$html =~ s/<textarea(.*?)>(.*?)<\/textarea>/\[code]$2\[\/code]/sgmi;
$html =~ s/<b>(.*?)<\/b>/\[b]$1\[\/b]/gi;
$html =~ s/<i>(.*?)<\/i>/\[i]$1\[\/i]/gi;
$html =~ s/<u>(.*?)<\/u>/\[u]$1\[\/u]/gi;
$html =~ s/<em>(.*?)<\/em>/\[i]$1\[\/i]/gi;
$html =~ s/<strong>(.*?)<\/strong>/\[b]$1\[\/b]/gi;
$html =~ s/<cite>(.*?)<\/cite>/\[i]$1\[\/i]/gi;
$html =~ s/<font color="(.*?)">(.*?)<\/font>/\[color=$1]$2\[\/color]/sgmi;
$html =~ s/<font color=(.*?)>(.*?)<\/font>/\[color=$1]$2\[\/color]/sgmi;
$html =~ s/<link(.*?)>//gi;
$html =~ s/<li(.*?)>(.*?)<\/li>/\[\*]$2/gi;
$html =~ s/<ul(.*?)>/\[list]/gi;
$html =~ s/<\/ul>/\[\/list]/gi;
$html =~ s/<div>/\n/gi;
$html =~ s/<\/div>/\n/gi;
$html =~ s/<td(.*?)>/ /gi;
$html =~ s/<tr(.*?)>/\n/gi;

$html =~ s/<img(.*?)src="(.*?)"(.*?)>/\[img]$baseurl\/$2\[\/img]/gi;
$html =~ s/<a(.*?)href="(.*?)"(.*?)>(.*?)<\/a>/\[url=$baseurl\/$2]$4\[\/url]/gi;
$html =~ s/\[url=$baseurl\/http:\/\/(.*?)](.*?)\[\/url]/\[url=http:\/\/$1]$2\[\/url]/gi;
$html =~ s/\[img]$baseurl\/http:\/\/(.*?)\[\/img]/\[img]http:\/\/$1\[\/img]/gi;

$html =~ s/<head>(.*?)<\/head>//sgmi;
$html =~ s/<object>(.*?)<\/object>//sgmi;
$html =~ s/<script(.*?)>(.*?)<\/script>//sgmi;
$html =~ s/<style(.*?)>(.*?)<\/style>//sgmi;
$html =~ s/<title>(.*?)<\/title>//sgmi;
$html =~ s/<!--(.*?)-->/\n/sgmi;

$html =~ s/\/\//\//gi;
$html =~ s/http:\//http:\/\//gi;
$html =~ s/https:\//https:\/\//gi;

$html =~ s/<(?:[^>'"]*|(['"]).*?\1)*>//gsi;
$html =~ s/\r\r//gi;
$html =~ s/\[img]\//\[img]/gi;
$html =~ s/\[url=\//\[url=/gi;

15
これを行わないでください。お願いします。
不正行為者、

68

(x)HTMLを解析するRegExpメソッドの質問について、いくつかの制限について話したすべての人への答えは次のとおりです。NOBODY再帰について話したので、この強力な武器の力を支配する十分な訓練を受けていません。

RegExpにとらわれない同僚が私にこのディスカッションを通知しました。これは、この古くてホットなトピックに関するWebでの最初のものではありません。

いくつかの投稿を読んだ後、私が最初に行ったのは、このスレッドで「?R」文字列を探すことでした。2つ目は、「再帰」について検索することでした。
いいえ、聖なる牛、一致は見つかりませんでした。
パーサーが組み込まれている主なメカニズムについては誰も触れていないので、誰もその要点を得られないことにすぐに気づきました。

(x)HTMLパーサーが再帰を必要とする場合、再帰なしのRegExpパーサーは目的のために十分ではありません。シンプルな構成です。

RegExpブラックアートを習得するのは難しいため、片方の手でWeb全体をキャプチャするための個人用ソリューションを試してテストしている間に、取り残された可能性がさらにあるかもしれません。

ここに魔法のパターンがあります:

$pattern = "/<([\w]+)([^>]*?)(([\s]*\/>)|(>((([^<]*?|<\!\-\-.*?\-\->)|(?R))*)<\/\\1[\s]*>))/s";

やってみなよ。
これはPHP文字列として記述されるため、「s」修飾子を使用すると、クラスに改行が含まれます。
ここにあるPHPマニュアルのサンプルノート私は1月に書いた:リファレンス

(注意してください、「m」修飾子を誤って使用したことに注意してください。^または$アンカーが使用されていないため、RegExpエンジンによって破棄されますが、削除する必要があります)。

ここで、この方法の限界について、より知識のある観点から話すことができます。

  1. RegExpエンジンの特定の実装によると、再帰は、解析されるネストされたパターン数に制限がある場合がありますが、使用される言語によって異なります
  2. 破損した(x)HTMLは重大なエラーを引き起こしませんが、サニタイズされません。

とにかくそれはただのRegExpパターンですが、それは多くの強力な実装を開発する可能性を開示しています。
このパターンは、フレームワークに組み込んだテンプレートエンジンの再帰降下パーサーを強化するために作成しました。パフォーマンスは、実行時間とメモリ使用量の両方で非常に優れています(同じ構文を使用する他のテンプレートエンジンとは関係ありません)。


35
これを「属性内のより大を許可しない正規表現」ビンに入れます。<input value = "is 5> 3?"と照合してください。/>
ガレス、

68
そのようなものを本番コードに入れると、メンテナによって撃たれる可能性があります。陪審員は決して彼を有罪とはしなかった。
aehiilrs 2010

30
正規表現は定義上、再帰的ではないため機能しません。正規表現に再帰演算子を追加すると、CFGの構文が低下します。無関係な機能ですでに溢れているものに再帰を激しく挿入するのではなく、最初から再帰的になるように設計されたものを使用しないのはなぜですか?
ウェルボグ

16
私の異論は、時間を費やした機能の1つではありません。RegExの問題は、cutseyの小さな1ライナーを投稿するまでに、より効率的に何かをしたように見えることです(「1行のコードを参照してください!」)。そしてもちろん、誰もがカンニングシートで費やした30時間(または3時間)について言及し、(できれば)入力のあらゆる可能な順列をテストしたことについて言及していません。そして、すべてを乗り越えたら、メンテナーがコードを理解または検証しようとするとき、彼らは単にそれを見て、それが正しいことを確認することができません。表現を分析し、本質的に何度も再テストする必要があります...
Oorang

15
...それが良いことを知るために。そして、それは正規表現が得意な人でも起こります。そして正直なところ、圧倒的多数の人々はそれをよく知らないのではないかと思います。あなたは最も悪名高いメンテナンスの悪夢の1つを取り、それを他のメンテナンスの悪夢である再帰と組み合わせます。私は自分のプロジェクトで本当に必要なものはもう少し賢くない人だと私は思います。目標は、悪意のあるプログラマがコードベースを壊すことなく維持できるコードを記述することです。最も一般的な分母にコーディングするのは間違いです。しかし、優秀な人材を採用することは困難であり、多くの場合...
Oorang

62

多くの人がすでに指摘したように、HTMLは通常の言語ではないため、解析が非常に困難になります。これに対する私の解決策は、整頓されたプログラムを使用してそれを通常の言語に変換し、XMLパーサーを使用して結果を利用することです。これには良いオプションがたくさんあります。私のプログラムは、HTMLをXMLに変換し、次にJaxenをxpathに変換するjtidyライブラリーを備えたJavaを使用して作成されています。


61
<\s*(\w+)[^/>]*>

パーツの説明:

<:開始文字

\s*:タグ名の前に空白がある可能性があります(醜いですが可能です)。

(\w+):タグには文字と数字(h1)を含めることができます。まあ、\w「_」にもマッチしますが、害はないと思います。好奇心が強い場合は、代わりに([a-zA-Z0-9] +)を使用してください。

[^/>]*:クローズするまで>、および/クローズするまで>

>: 閉鎖 >

無関係

そして、正規表現を過小評価している仲間たちに、彼らは通常の言語と同じくらい強力だと言っています:

a n ba n ba nは規則的ではなく、コンテキストフリーでもないため、^(a+)b\1b\1$

FTWの逆参照!


@GlitchMr、それが彼のポイントでした。現代の正規表現は、技術的には正規ではなく、そうである理由もありません。
アラナクション2013

3
@alanaktion:「最新の」正規表現(読み取り:Perl拡張を使用)は、以下と一致できませんO(MN)(Mは正規表現の長さ、Nはテキストの長さ)。後方参照はその原因の1つです。awkの実装には後方参照がなく、O(MN)時間内にすべてに一致します。
Konrad Borowski、2013

56

これらのタグを(構文解析の野心なしで)単に検索しようとしている場合は、次の正規表現を試してください。

/<[^/]*?>/g

私はそれを30秒で書いて、ここでテストしました:http : //gskinner.com/RegExr/

それはあなたが言及したタグのタイプと一致しますが、あなたが無視したいと言ったタイプは無視します。


2
\/>代わりにという意味だと思います\\>
Justin Morgan

いいえ、\>私が意図したとおりです。元の投稿の正規表現を編集するつもりはありませんでした。
ロニーベスト

2
参考までに、山かっこをエスケープする必要はありません。もちろん、とにかく彼らを逃れるのは害はありませんが、あなたが避けたはずの混乱を見てください。;)
アランムーア

何か特別なキャラクターかどうか分からないときは、不必要に逃げることがあります。回答を編集しました。同じように機能しますが、より簡潔です。
ロニーベスト

これを今見ると、なぜあなたが何を意味していると思ったのかわかりません\/。多分私はあなたが否定的なフィルターパターンを提供していると思った。
ジャスティンモーガン

54

末尾に「/」を付けずにタグを一致させようとしているようです。これを試して:

<([a-zA-Z][a-zA-Z0-9]*)[^>]*(?<!/)>

8
これは動作しません。入力 '<xa = "<b>" /> <y>'の場合、一致はxとyですが、xは終了します。
2011年

51

特に正確さが最優先の場合(たとえば、処理がセキュリティに影響を与える可能性がある場合)、HTMLを処理するときは、通常、プログラミング時に正規表現ではなく専用のパーサーとAPIを使用するのが最善です。ただし、XMLスタイルのマークアップは正規表現で処理してはならないという独断的な見方には同意しません。テキストエディターで1回限りの編集を行ったり、破損したXMLファイルを修正したり、XMLに似ているが完全ではないファイル形式を処理したりする場合など、正規表現が仕事に最適なツールとなる場合があります。知っておくべき問題がいくつかありますが、それらは乗り越えられないわけではなく、必ずしも関連性さえありません。

<([^>"']|"[^"]*"|'[^']*')*>私が今述べたようなケースでは、通常のような単純な正規表現で十分です。これはすべてを考慮した単純なソリューションですが、>属性値にエンコードされていない記号を正しく許可します。たとえばtableタグを探している場合は、として適応できます</?table\b([^>"']|"[^"]*"|'[^']*')*>

より「高度な」HTML正規表現がどのように見えるかを理解するために、実際のブラウザの動作とHTML5解析アルゴリズムをエミュレートするかなり信頼できる作業を以下に示します。

</?([A-Za-z][^\s>/]*)(?:=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)|[^>])*(?:>|$)

以下は、XMLタグのかなり厳密な定義と一致します(ただし、XML名で許可されているUnicode文字の完全なセットは考慮されていません)。

<(?:([_:A-Z][-.:\w]*)(?:\s+[_:A-Z][-.:\w]*\s*=\s*(?:"[^"]*"|'[^']*'))*\s*/?|/([_:A-Z][-.:\w]*)\s*)>

確かに、これらは周囲のコンテキストやいくつかのエッジケースを考慮していませんが、本当にそうしたい場合は(たとえば、別の正規表現の一致を検索することによって)対処できます。

結局のところ、そのツールが正規表現である場合でも、ジョブに最適なツールを使用してください。


49

そのために正規表現を使用することは適切で効果的ではありませんが、正規表現が単純な一致の問題に対する迅速な解決策を提供する場合があります。

Steven Levithanによって書かれた最も内側のHTML要素のマッチングに関する決定的なブログ投稿があります。

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