C#正規表現を使用してHTMLタグを削除する


139

山かっこを含むすべてのHTMLタグをC#の正規表現で置換/削除するにはどうすればよいですか?誰かがコードを手伝ってくれませんか?



あなたはそれを示していませんが、タグを削除するだけでなく、スクリプトとスタイル要素も完全に削除したいと思います。以下のHTML Agility Packの回答はタグを削除するのに適していますが、スクリプトとスタイルを削除するには、stackoverflow.com / questions / 13441470
John

1
重複として示された質問には多くの情報(およびトニーザポニー!)がありますが、すべてのタグではなく、開始タグのみを要求しました。したがって、技術的に重複しているかどうかはわかりません。とは言っても、答えは同じです。
goodeye 2014年

回答:


154

前述のように、XMLまたはHTMLドキュメントの処理には正規表現を使用しないでください。ネストされた構造を一般的な方法で表現する方法がないため、HTMLおよびXMLドキュメントではあまり機能しません。

以下を使用できます。

String result = Regex.Replace(htmlDocument, @"<[^>]*>", String.Empty);

これはほとんどの場合に機能しますが、これが期待どおりに機能しない場合があります(たとえば、山括弧を含むCDATA)。


13
これは素朴な実装です。つまり、<div id = "x <4>">は残念ながら有効なhtmlです。ハンドルほとんど正気の場合...しかし
ライアンEmerle

8
すでに述べたように、この表現が失敗する場合があることを認識しています。一般的なケースが正規表現でエラーなしに処理できるかどうかさえわかりません。
DanielBrückner、

1
いいえ、これはすべての場合に失敗します!その貪欲。
ジェイク

13
@暗号、なぜ貪欲が問題だと思いますか?一致が有効なHTMLタグの先頭から始まると仮定すると、そのタグの末尾を超えて拡張されることはありません。それが[^>]の目的です。
アランムーア

1
@AlanMoore htmlは「通常の言語」ではありません。つまり、有効なhtmlであるすべてのものを正規表現と適切に一致させることはできません。参照:stackoverflow.com/questions/590747/...
Kache

78

正解はそれではなく、HTML Agility Packを使用することです。

追加するように編集:

恥ずかしがらずにjesseによる以下のコメントを盗み、今回も質問に不適切に回答したことで非難されないようにするために、HTMLの最も不完全な、気まぐれなビットでも機能するHTML Agility Packを使用したシンプルで信頼できるスニペットを次に示します。

HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(Properties.Resources.HtmlContents);
var text = doc.DocumentNode.SelectNodes("//body//text()").Select(node => node.InnerText);
StringBuilder output = new StringBuilder();
foreach (string line in text)
{
   output.AppendLine(line);
}
string textOnly = HttpUtility.HtmlDecode(output.ToString());

HTMLを解析するために正規表現を使用する防御可能なケースはほとんどありません。HTMLは、従来とは異なる正規表現エンジンでさえ提供するのが非常に面倒なコンテキスト認識なしでは正しく解析できないためです。RegExを使用すると、途中で取得できますが、手動で確認する必要があります。

HTML Agility Packは、HTMLを単純な文脈自由文法として扱うことから生じる可能性のある異常を手動で修正する必要性を減らす堅牢なソリューションを提供できます。

正規表現を使用すると、たいていの場合、たいていの場合に必要なものが得られますが、非常に一般的なケースでは失敗します。HTML Agility Packよりも優れた/より速いパーサーを見つけることができる場合は、それを試してください。しかし、世界をより壊れたHTMLハッカーにさらさないでください。


27
HTML Agility Packは、HTMLの操作に関連するすべてに対する答えではありません(たとえば、HTMLコードのフラグメントのみを操作したい場合はどうでしょうか?)。
PropellerHead

7
これはHTMLのフラグメントでかなりうまく機能し、元のポスターで説明されているシナリオに最適なオプションです。一方、正規表現は理想的なHTMLでのみ機能し、HTMLの文法は規則的でないため、完全に有効なHTMLで機能しなくなります。彼がRubyを使用している場合でも、私はnokogiriやhpricot、あるいはPythonのbeautifulsoupを提案したでしょう。文法のない任意のテキストストリームではなく、HTMLをHTMLのように扱うことが最善です。
JasonTrue

1
HTMLは通常の文法ではないため、正規表現だけで解析することはできません。正規表現は字句解析に使用できますが、解析には使用できません。とても簡単です。言語学者たちは、HTMLさえ存在する前にこれに同意したでしょう。
JasonTrue

20
これは意見の問題ではありません。正規表現を使用すると、たいていの場合、たいていの場合は必要なものが得られますが、非常に一般的なケースでは失敗します。HTML Agility Packよりも優れた/より速いパーサーを見つけることができる場合は、それを試してください。しかし、世界をより壊れたHTMLハッカーにさらさないでください。
JasonTrue

2
HTMLを解析しないと、HTMLタグを確実に正しく識別することができません。HTMLの文法をすべて理解していますか?他の回答が示唆する「かなり近づく」ための邪悪なハックを参照し、なぜそれを維持する必要があるのか​​を教えてください。サンプル入力に対してハッキーなクイック試行が機能するため、私に反対票を投じても、ソリューションが正しくなります。&gt;でネガティブマッチングを使用してHTMLコンテンツからレポートを生成したり、CSS参照を修正したりするために、時々正規表現を使用しました。エラーの可能性を制限しますが、追加の検証を行いました。それは一般的な目的ではありませんでした。
JasonTrue

38

質問は広範すぎて明確に答えることができません。Webページのような実際のHTMLドキュメントからすべてのタグを削除することについて話しているのですか?もしそうなら、あなたはする必要があります:

  • <!DOCTYPE宣言または<?xmlプロローグ(存在する場合)を削除する
  • すべてのSGMLコメントを削除する
  • HEAD要素全体を削除する
  • すべてのSCRIPTおよびSTYLE要素を削除する
  • FORMおよびTABLE要素でGrabthar-knows-whatを実行する
  • 残りのタグを削除します
  • <![CDATA [and]]>シーケンスをCDATAセクションから削除しますが、その内容はそのままにします

それは私の頭の上にあります-もっとあると確信しています。これをすべて完了すると、単語、文、段落がいくつかの場所で一緒に実行され、他の場所では役に立たない空白の大きなチャンクができます。

ただし、フラグメントのみを使用していて、すべてのタグを削除するだけで済むと仮定すると、次の正規表現を使用します。

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

独自の代替で単一引用符と二重引用符で囲まれた文字列を一致させることで、属性値の山括弧の問題に対処できます。ライアンの答えの正規表現のように、タグ内の属性名やその他のものと明示的に一致させる必要はないと思います。最初の選択肢はそのすべてを処理します。

これらの(?>...)構成について疑問に思っている場合は、それらはアトミックグループです。これらは正規表現を少し効率的にしますが、より重要なことに、ランナウェイバックトラッキングを防止します。私はそれがここで問題になるとは本当に思っていませんが、私がそれを言わなければ、他の誰かがそうするでしょう。;-)

もちろん、この正規表現は完璧ではありませんが、おそらく必要になるほど優れているでしょう。


1
これは断然最良の答えです。投稿者の質問に回答し、特定のタスクに正規表現を使用しない理由を説明します。よくやった。
JWilliams


18

@JasonTrueは正解です。HTMLタグの削除は、正規表現を介して行うべきではありません。

HtmlAgilityPackを使用してHTMLタグを削除するのは非常に簡単です。

public string StripTags(string input) {
    var doc = new HtmlDocument();
    doc.LoadHtml(input ?? "");
    return doc.DocumentNode.InnerText;
}

1
私はこれに少し遅れていますが、これはWordや他のオフィス製品で作成されたXMLなどでも機能することを述べておきたいと思います。Word xmlに対処する必要があった人なら誰でも、これが非常に役立つので、特に私が必要としているコンテンツからタグを削除する必要がある場合は、これを使用して検討することをお勧めします。
スティーブペティファー2013

他のすべてが失敗したように思われたとき、この簡単なコードスニペットがその日を救った。ありがとう!
Ted Krapf

13

Jasonの応答をエコーし​​たいのですが、いくつかのHtmlを単純に解析してテキストコンテンツを引き出す必要がある場合があります。

私はリッチテキストエディターによって作成されたHtmlでこれを行う必要がありました。

この場合、一部のタグのコンテンツだけでなく、タグ自体も削除する必要がある場合があります。

私の場合、タグはこのミックスに投入されました。一部の人は、私の(ごくわずかに)単純ではない実装が有用な出発点であると考えるかもしれません。

   /// <summary>
    /// Removes all html tags from string and leaves only plain text
    /// Removes content of <xml></xml> and <style></style> tags as aim to get text content not markup /meta data.
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public static string HtmlStrip(this string input)
    {
        input = Regex.Replace(input, "<style>(.|\n)*?</style>",string.Empty);
        input = Regex.Replace(input, @"<xml>(.|\n)*?</xml>", string.Empty); // remove all <xml></xml> tags and anything inbetween.  
        return Regex.Replace(input, @"<(.|\n)*?>", string.Empty); // remove any tags but not there content "<p>bob<span> johnson</span></p>" becomes "bob johnson"
    }

1
明らかなクロスプラットフォームの改行の問題は別として、コンテンツが区切られている場合、貪欲な量指定子を持つことは遅くなります。最初の2つと最後の2つに修飾子を付けるなど<xml>.*(?!</xml>)</xml>を使用します。最初のものは、最初のタグ名のキャプチャされた代替と、負の先読みと最後のタグのそれへの後方参照によって結合することもできます。RegexOptions.SingleLine<[^>]*>
ChrisF 2013年

5

次のURLで正規表現方法を試してください:http : //www.dotnetperls.com/remove-html-tags

/// <summary>
/// Remove HTML from string with Regex.
/// </summary>
public static string StripTagsRegex(string source)
{
return Regex.Replace(source, "<.*?>", string.Empty);
}

/// <summary>
/// Compiled regular expression for performance.
/// </summary>
static Regex _htmlRegex = new Regex("<.*?>", RegexOptions.Compiled);

/// <summary>
/// Remove HTML from string with compiled Regex.
/// </summary>
public static string StripTagsRegexCompiled(string source)
{
return _htmlRegex.Replace(source, string.Empty);
}



-1

このメソッドを使用してタグを削除します。

public string From_To(string text, string from, string to)
{
    if (text == null)
        return null;
    string pattern = @"" + from + ".*?" + to;
    Regex rx = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
    MatchCollection matches = rx.Matches(text);
    return matches.Count <= 0 ? text : matches.Cast<Match>().Where(match => !string.IsNullOrEmpty(match.Value)).Aggregate(text, (current, match) => current.Replace(match.Value, ""));
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.