使用C#正则表达式删除HTML标签


139

如何使用C#正则表达式替换/删除所有HTML标签,包括尖括号?有人可以帮我提供代码吗?



您没有指示它,但是我推断您还希望完全删除脚本和样式元素,而不仅仅是删除标签。下面的HTML Agility Pack答案对于删除标记是正确的,但是要删除脚本和样式,您还需要诸如stackoverflow.com/questions/13441470/…之类的
John

1
表示为重复项的问题有很多信息(还有Tony the Pony!),但是它只要求打开标签,而不是所有标签。所以我不确定从技术上讲它是重复的。也就是说,答案是相同的:不。
眼神

Answers:


154

如前所述,您不应使用正则表达式来处理XML或HTML文档。它们在HTML和XML文档中表现不佳,因为无法以一般方式表达嵌套结构。

您可以使用以下内容。

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

这在大多数情况下都可以使用,但是在某些情况下(例如,包含尖括号的CDATA)将无法正常使用。


13
这是一个幼稚的实现。.不幸的是,<div id =“ x <4>”>是有效的html。处理大多数理智的情况下,虽然..
瑞安Emerle

8
如上所述,我知道在某些情况下此表达式将失败。我什至不确定一般情况是否可以由任何正则表达式处理而没有错误。
DanielBrückner2009年

1
不,这在所有情况下都会失败!它的贪婪。
杰克

13
@Cipher,您为什么认为贪婪是一个问题?假设匹配从有效HTML标记的开头开始,那么它将永远不会超出该标记的结尾。这就是[^>]的目的。
艾伦·摩尔

1
@AlanMoore html不是“常规语言”,即您不能正确地将所有有效html与正则表达式匹配。见:stackoverflow.com/questions/590747/...
Kache

78

正确的答案是不要这样做,请使用HTML Agility Pack

编辑添加:

为了毫不掩饰地从jesse的下面的评论中窃取,并避免被指责在所有这些时间之后都未回答问题,以下是使用HTML Agility Pack的一个简单,可靠的代码段,该代码段甚至可以用于格式最不完整,反复无常的HTML代码:

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一样对待,而不是一些没有语法的任意文本流。
2009年

1
HTML不是常规语法,因此不能仅使用常规表达式进行解析。您可以将正则表达式用于词法分析,但不能用于语法分析。真的就是这么简单。语言学家甚至在HTML尚未存在之前就已经对此达成共识。
JasonTrue 2011年

20
这不是意见问题。正则表达式在大多数情况下可以为您提供大部分所需的信息,但是在非常常见的情况下它将失败。如果您能找到比HTML Agility Pack更好/更快的解析器,那就去吧,但是请不要让世界遭受更多破碎的HTML骇客攻击。
JasonTrue 2011年

2
如果不分析HTML,就无法可靠地正确识别HTML标签。您了解HTML的所有语法吗?请参阅邪恶的技巧,以使其他答案暗示“非常接近”,并告诉我为什么您必须维护该技巧。拒绝我投票是因为对您的样本输入进行快速的尝试不会使您的解决方案正确。我偶尔会使用正则表达式从HTML内容生成报告,或者使用&gt;上的否定匹配来修正一些CSS参考。为了限制出错的机会,但是我们进行了额外的验证;这不是通用目的。
JasonTrue 2011年

38

这个问题太广泛了,无法确切地回答。您是在谈论从真实的HTML文档(例如网页)中删除所有标签吗?如果是这样,您将必须:

  • 删除<!DOCTYPE声明或<?xml序言(如果存在)
  • 删除所有SGML注释
  • 删除整个HEAD元素
  • 删除所有SCRIPT和STYLE元素
  • 用Form和TABLE元素做Grabthar-知道什么
  • 删除其余标签
  • 从CDATA节中删除<![CDATA [和]]>序列,但不保留其内容

那只是我的头上了-我敢肯定还有更多。完成所有这些操作后,您最终将在某些地方同时使用单词,句子和段落,而在其他地方则使用了大量的无用空格。

但是,假设您只使用一个片段,而只需删除所有标签就可以摆脱困境,这是我要使用的正则表达式:

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

用单引号和双引号引起来的字符串进行匹配足以解决属性值中尖括号的问题。我认为不需要显式匹配标记中的属性名称和其他内容,就像Ryan的答案中的regex一样。第一种方法可以处理所有这些问题。

如果您想知道这些(?>...)构造,它们就是原子团。它们使regex更加有效,但是更重要的是,它们防止了失控的回溯,当您混合交替和嵌套的量词时,您应该始终注意这一点,就像我所做的那样。我真的不认为这会是一个问题,但是我知道,如果我不提的话,其他人也会。;-)

当然,此正则表达式并不完美,但它可能与您需要的一样好。


1
到目前为止,这是最好的答案。您回答发布者的问题,并解释为什么不应该对给定任务使用正则表达式。做得好。
JWilliams 2012年


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的任何人都可以很好地使用它,因为它确实有很大帮助,特别是如果您需要从内容中剥离标签,而这正是我所需要的。
史蒂夫·佩蒂弗

当所有其他方法似乎都失败了时,这个简单的代码片段挽救了这一天。谢谢!
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
除了明显的跨平台换行问题之外,对内容进行定界时,使用不合要求的量词也是很慢的。使用之类的东西<xml>.*(?!</xml>)</xml>RegexOptions.SingleLine修改前两个和<[^>]*>最后。也可以通过捕获的第一个标签名称的替换以及在否定的超前标签和最终标签中的反向引用来组合第一个标签。
克里斯夫·

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);
}

3

用这个..

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


-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, ""));
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.