【问题标题】:How can I strip HTML tags from a string in ASP.NET?如何从 ASP.NET 中的字符串中去除 HTML 标记?
【发布时间】:2010-10-21 14:32:34
【问题描述】:

使用 ASP.NET,我怎样才能可靠地从给定字符串中去除 HTML 标记(即不使用正则表达式)?我正在寻找类似 PHP 的 strip_tags。

示例:

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

输出:

“你好”

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

【问题讨论】:

标签: c# asp.net html regex string


【解决方案1】:

如果它只是从字符串中剥离 所有 HTML 标记,那么 reliably 也适用于正则表达式。替换:

<[^>]*(>|$)

全局使用空字符串。之后不要忘记规范化字符串,替换:

[\s\r\n]+

用一个空格,并修剪结果。可选择将任何 HTML 字符实体替换回实际字符​​。

注意:

  1. 有一个限制:HTML 和 XML 允许在属性值中使用 &amp;gt;。此解决方案将在遇到此类值时返回损坏的标记。
  2. 该解决方案在技术上是安全的,例如: 结果将永远不会包含任何可用于执行跨站点脚本或破坏页面布局的内容。就是不是很干净。
  3. 与所有 HTML 和正则表达式一样:
    如果您必须在所有情况下正确处理,请使用 a proper parser。

【讨论】:

  • 虽然没有被要求,但我想很多读者也会想去掉 HTM 编码,比如&amp;quote;。为此,我将它与WebUtility.HtmlDecode 结合使用(这反过来不会删除标签)。在标签删除后使用它,因为它可能会重写&amp;gt; 和&amp;lt;。例如。 WebUtility.HtmlDecode(Regex.Replace(myTextVariable, "&lt;[^&gt;]*(&gt;|$)", string.Empty))
  • @YahooSerious 感谢您提供示例。这很好用。谢谢。
  • Html Agility Pack 是要走的路,我在网络表单中使用它来剥离整个网页以使用内容!
  • @YahooSerious 这将允许一个 XSS 向量但是 >脚本 alert("XXS"); script>
  • @Heather 非常好。实体解码后必须再次进行 HTML 标签剥离。
【解决方案2】:

您也可以使用 AngleSharp 来执行此操作,它是 HtmlAgilityPack 的替代品(并不是说 HAP 不好)。从 HTML 源中获取文本比 HAP 更容易使用。

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

您可以查看key features 部分,他们在其中提出了比 HAP“更好”的案例。我认为在大多数情况下,对于当前问题来说,这可能是矫枉过正,但它仍然是一个有趣的选择。

【讨论】:

    【解决方案3】:
    using System.Text.RegularExpressions;
    
    string str = Regex.Replace(HttpUtility.HtmlDecode(HTMLString), "<.*?>", string.Empty);
    

    【讨论】:

      【解决方案4】:

      对于第二个参数,即保留一些标签,你可能需要一些这样的代码,使用 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/

      【讨论】:

        【解决方案5】:

        我查看了此处建议的基于正则表达式的解决方案,除了最微不足道的情况外,它们并没有让我充满信心。一个属性中的尖括号就可以打破,更不用说来自野外的格式错误的HTML了。那么像&amp;amp; 这样的实体呢?如果要将 HTML 转换为纯文本,还需要对实体进行解码。

        所以我提出下面的方法。

        使用HtmlAgilityPack,此扩展方法有效地从 html 片段中剥离所有 HTML 标记。还解码 HTML 实体,如 &amp;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 标记的内容(&lt;script&gt;、&lt;style&gt;、&lt;svg&gt;、&lt;head&gt;、&lt;object&gt; 浮现在脑海中!)因为它们可能不包含我们所追求的可读内容。你在那里做什么取决于你的情况和你想走多远,但使用 HtmlAgilityPack 将选定的标签列入白名单或黑名单将非常简单。

        如果您将内容呈现回 HTML 页面,请确保您了解 XSS 漏洞和how to prevent it - 即始终对返回到 HTML 页面的任何用户输入的文本进行编码(&amp;gt; 变为 &amp;gt;等)。

        【讨论】:

          【解决方案6】:

          只需使用string.StripHTML();

          【讨论】:

          • 正如@Serpiton 指出的那样,BCL 中没有这样的方法。您能否指出该方法的实现或提供您自己的实现?
          【解决方案7】:

          对于那些抱怨 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;
              }
          }
          

          【讨论】:

            【解决方案8】:
            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
            

            【讨论】:

            • 不适用于很多情况,包括非 unix 换行符。
            【解决方案9】:

            对于那些不能使用 HtmlAgilityPack 的人来说,.NETs XML 阅读器是一种选择。这在格式良好的 HTML 上可能会失败,因此请始终添加带有 regx 的 catch 作为备份。请注意,这并不快,但它确实为老派调试提供了一个很好的机会。

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

            【讨论】:

              【解决方案10】:

              现在就去下载 HTMLAgilityPack! ;) Download 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;
                          }
              

              【讨论】:

              • 您甚至可以查询每个text() 节点,修剪内容和字符串。加入空格。 IEnumerable&lt;string&gt; allText = doc.DocumentNode.SelectNodes("//text()").Select(n =&gt; n.InnerText.Trim())
              • 或简单地使用 doc.DocumentNode.InnerText,虽然这似乎与空格处理有一些问题......
              • 为什么要检查if (doc == null)?这总是假的,不是吗?
              【解决方案11】:

              我在 c# 中编写了一个非常快的方法,它击败了正则表达式。它托管在 CodeProject 上的an article。

              除了更好的性能之外,它的优势还在于能够替换命名和编号的 HTML 实体(例如 &amp;amp;amp; 和 &amp;203;)以及替换注释块等等。

              请阅读related article on CodeProject。

              谢谢。

              【讨论】:

                【解决方案12】:
                string result = Regex.Replace(anytext, @"<(.|\n)*?>", string.Empty);
                

                【讨论】:

                  【解决方案13】:
                  Regex.Replace(htmlText, "<.*?>", string.Empty);
                  

                  【讨论】:

                  • 有很多问题 - 不能处理包含 的属性,并且不能很好地处理跨越多行的标签,除非使用 RegexOptions.SingleLine 运行。
                  • 不,使用“]*>”。
                  【解决方案14】:

                  我已经在 asp.net 论坛上发布了这个,它似乎仍然是最简单的解决方案之一。我不能保证它是最快或最有效的,但它非常可靠。 在 .NET 中,您可以使用 HTML Web 控件对象本身。您真正需要做的就是将您的字符串插入到一个临时的 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="foo";并且 InnerText 的值为 "foo" :(
                  • 不要这样做。此解决方案将未编码的 html 直接注入到输出中。这将使您对跨站点脚本攻击敞开大门 - 您刚刚允许任何可以更改 html 字符串的人将任意 html 和 javascript 注入您的应用程序!
                  猜你喜欢
                  • 2014-11-16
                  • 2013-03-07
                  • 2013-02-21
                  • 2012-08-07
                  • 2015-10-07
                  • 2010-10-02
                  • 1970-01-01
                  • 2010-09-19
                  相关资源
                  最近更新 更多