如何从ASP.NET中的字符串中删除HTML标签?


123

使用ASP.NET,如何可靠地剥离给定字符串中的HTML标签(即不使用正则表达式)?我正在寻找类似PHP的东西strip_tags

例:

<ul><li>Hello</li></ul>

输出:

“你好”

我尝试不重新发明轮子,但是到目前为止,我还没有找到任何满足我需求的东西。


我可以想象PHP strip_tags在幕后使用正则表达式!
stevehipwell 2009年

10
@Daniel:因为正则表达式在这方面很不好,特别是如果您有嵌套的话。
Joel Coehoorn

嗯,无论是在官方注释还是注释上,PHP的Strip_Tags看起来都不是特别可靠:uk.php.net/strip_tags
Zhaph-Ben Duguid

Answers:


112

如果只是从字符串中剥离所有 HTML标记,则这也可以与regex 可靠地一起工作。更换:

<[^>]*(>|$)

与空字符串,全局。不要忘了之后将字符串标准化,替换为:

[\s\r\n]+

与单个空格,并修剪结果。(可选)将所有HTML字符实体替换回实际字符​​。

注意事项

  1. 有一个限制:HTML和XML允许>使用属性值。当遇到这样的值时,此解决方案返回损坏的标记。
  2. 该解决方案在技术上是安全的,如下所示:结果永远不会包含任何可用于跨站点脚本编写或破坏页面布局的内容。只是不是很干净。
  3. 与所有HTML和regex一样:如果必须在所有情况下正确
    使用解析器,请使用适当的解析器

52
尽管没有要求,但我认为许多读者也希望剥离HTM编码,例如&quote;。我WebUtility.HtmlDecode为此与它结合(反过来也不会删除标签)。删除标记后使用它,因为它可能会重写&gt;&lt;。EGWebUtility.HtmlDecode(Regex.Replace(myTextVariable, "<[^>]*(>|$)", string.Empty))
雅虎严重的

@YahooSerious感谢您提供示例。这很好。谢谢。
SearchForKnowledge

HTML Agility Pack是必经之路,我早在Webforms中就使用过它来剥离整个网页以使用内容!
Bojangles

3
@YahooSerious这将允许XSS向量,但是&gt; 脚本&lt; alert(“ XXS”); &gt; /脚本&lt; 不会被正则表达式清除,而是由HtmlDecode转换为<script> alert(“ XXS”); </ script>

1
@希瑟·很好。实体解码后,必须再次进行HTML标签剥离。
Tomalak

76

立即下载HTMLAgilityPack!;) 下载LInk

这使您可以加载和解析HTML。然后,您可以浏览DOM并提取所有属性的内部值。严重的是,最多最多需要10行代码。它是那里最大的免费.net库之一。

这是一个示例:

            string htmlContents = new System.IO.StreamReader(resultsStream,Encoding.UTF8,true).ReadToEnd();

            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(htmlContents);
            if (doc == null) return null;

            string output = "";
            foreach (var node in doc.DocumentNode.ChildNodes)
            {
                output += node.InnerText;
            }

2
您甚至可以查询每个text()节点,修剪内容和字符串。IEnumerable<string> allText = doc.DocumentNode.SelectNodes("//text()").Select(n => n.InnerText.Trim())
jessehouwing 2012年

或简单地使用doc.DocumentNode.InnerText,尽管在处理空格方面存在一些问题……
jessehouwing 2012年

17
为什么要if (doc == null)检查?这总是假的,不是吗?
阿瑟斯(Avesse)2012年


11
protected string StripHtml(string Txt)
{
    return Regex.Replace(Txt, "<(.|\\n)*?>", string.Empty);
}    

Protected Function StripHtml(Txt as String) as String
    Return Regex.Replace(Txt, "<(.|\n)*?>", String.Empty)
End Function

2
在很多情况下(包括非unix换行符)不起作用。
克里斯夫·

6

我已经将其发布在asp.net论坛上,它似乎仍然是最简单的解决方案之一。我不能保证它是最快或最有效的,但它确实可靠。在.NET中,您可以使用HTML Web Control对象本身。您真正需要做的就是将字符串插入到临时HTML对象(例如DIV)中,然后使用内置的“ InnerText”来获取标记中未包含的所有文本。请参见下面的简单C#示例:


System.Web.UI.HtmlControls.HtmlGenericControl htmlDiv = new System.Web.UI.HtmlControls.HtmlGenericControl("div");
htmlDiv.InnerHtml = htmlString;
String plainText = htmlDiv.InnerText;

这似乎不起作用,我使用简单的InnerHtml =“ <b> foo </ b>”测试了它;并且InnerText的值为“ <b> foo </ b>” :(
Axarydax

不要这样 该解决方案将未编码的html直接注入到输出中。这将使您对跨站点脚本攻击敞开大门-您刚刚允许任何可以更改html字符串的人向您的应用程序中注入任意html和javascript!
2015年


4

对于无法使用HtmlAgilityPack的用户,可以选择.NETs XML阅读器。尽管在格式正确的HTML上这可能会失败,所以请始终使用regx作为备份添加捕获。请注意,这并不是很快,但是确实为旧式调试提供了一个很好的机会。

public static string RemoveHTMLTags(string content)
    {
        var cleaned = string.Empty;
        try
        {
            StringBuilder textOnly = new StringBuilder();
            using (var reader = XmlNodeReader.Create(new System.IO.StringReader("<xml>" + content + "</xml>")))
            {
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Text)
                        textOnly.Append(reader.ReadContentAsString());
                }
            }
            cleaned = textOnly.ToString();
        }
        catch
        {
            //A tag is probably not closed. fallback to regex string clean.
            string textOnly = string.Empty;
            Regex tagRemove = new Regex(@"<[^>]*(>|$)");
            Regex compressSpaces = new Regex(@"[\s\r\n]+");
            textOnly = tagRemove.Replace(content, string.Empty);
            textOnly = compressSpaces.Replace(textOnly, " ");
            cleaned = textOnly;
        }

        return cleaned;
    }


1

对于那些对Michael Tiptop解决方案不满意的人来说,这是.Net4 +的解决方法:

public static string StripTags(this string markup)
{
    try
    {
        StringReader sr = new StringReader(markup);
        XPathDocument doc;
        using (XmlReader xr = XmlReader.Create(sr,
                           new XmlReaderSettings()
                           {
                               ConformanceLevel = ConformanceLevel.Fragment
                               // for multiple roots
                           }))
        {
            doc = new XPathDocument(xr);
        }

        return doc.CreateNavigator().Value; // .Value is similar to .InnerText of  
                                           //  XmlDocument or JavaScript's innerText
    }
    catch
    {
        return string.Empty;
    }
}

1
using System.Text.RegularExpressions;

string str = Regex.Replace(HttpUtility.HtmlDecode(HTMLString), "<.*?>", string.Empty);

0

我看过这里建议的基于正则表达式的解决方案,除了在最琐碎的情况下,它们没有使我充满信心。一个属性中的尖括号就足以打破它,更不用说野蛮格式错误的HTML了。那像这样的实体呢&amp;呢?如果要将HTML转换为纯文本,则也需要解码实体。

因此,我提出以下方法。

使用HtmlAgilityPack,此扩展方法可以有效地从html片段中剥离所有HTML标记。还可以解码HTML实体,例如&amp;。仅返回内部文本项,每个文本项之间都有一个新行。

public static string RemoveHtmlTags(this string html)
{
        if (String.IsNullOrEmpty(html))
            return html;

        var doc = new HtmlAgilityPack.HtmlDocument();
        doc.LoadHtml(html);

        if (doc.DocumentNode == null || doc.DocumentNode.ChildNodes == null)
        {
            return WebUtility.HtmlDecode(html);
        }

        var sb = new StringBuilder();

        var i = 0;

        foreach (var node in doc.DocumentNode.ChildNodes)
        {
            var text = node.InnerText.SafeTrim();

            if (!String.IsNullOrEmpty(text))
            {
                sb.Append(text);

                if (i < doc.DocumentNode.ChildNodes.Count - 1)
                {
                    sb.Append(Environment.NewLine);
                }
            }

            i++;
        }

        var result = sb.ToString();

        return WebUtility.HtmlDecode(result);
}

public static string SafeTrim(this string str)
{
    if (str == null)
        return null;

    return str.Trim();
}

如果你真的很认真的,你会想忽略某些HTML标签的内容太(<script><style><svg><head><object>浮现在脑海中!),因为它们可能不包含在这个意义上,我们是后可读的内容。您在该处执行的操作将取决于您的情况以及您要走多远,但是使用HtmlAgilityPack可以将选择的标签列入白名单或黑名单。

如果要将内容呈现回HTML页面,请确保您了解XSS漏洞以及如何防止它 -即始终对任何用户输入的文本进行编码,这些文本将呈现回HTML页面(>变为&gt;等)。


0

对于第二个参数,即保留一些标签,您可能需要使用HTMLagilityPack这样的代码:

public string StripTags(HtmlNode documentNode, IList keepTags)
{
    var result = new StringBuilder();
        foreach (var childNode in documentNode.ChildNodes)
        {
            if (childNode.Name.ToLower() == "#text")
            {
                result.Append(childNode.InnerText);
            }
            else
            {
                if (!keepTags.Contains(childNode.Name.ToLower()))
                {
                    result.Append(StripTags(childNode, keepTags));
                }
                else
                {
                    result.Append(childNode.OuterHtml.Replace(childNode.InnerHtml, StripTags(childNode, keepTags)));
                }
            }
        }
        return result.ToString();
    }

此页面上的更多说明:http : //nalgorithm.com/2015/11/20/strip-html-tags-of-an-html-in-c-strip_html-php-equivalent/


0

您也可以使用AngleSharp来完成此操作,它可以替代HtmlAgilityPack(不是说HAP不好)。比起HAP,从HTML源中获取文本要容易得多。

var parser = new HtmlParser();
var htmlDocument = parser.ParseDocument(source);
var text = htmlDocument.Body.Text();

您可以看一下关键功能部分,在这些部分中它们比HAP更好。我认为在大多数情况下,这对于当前问题可能是过大了,但仍然是一个有趣的选择。


-4

只需使用 string.StripHTML();


3
正如@Serpiton指出的那样,BCL中没有这样的方法。您能否指出该方法的实现或提供您自己的方法?
斯文·格罗森
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.