C#如何使用正则表达式删除XML/HTML注释

18

以下代码片段对我不起作用。

fragment = Regex.Replace(fragment, "<!--.*?-->", String.Empty , RegexOptions.Multiline  );
4个回答

28
将其更改为RegExOptions.Singleline,它将正常工作。 当不在Singleline模式下时,点匹配任何字符,除了换行符。
请注意,SinglelineMultiline不是互斥的。它们执行两个独立的操作。引用MSDN的话: 多行模式。更改^和$的含义,使它们分别匹配任何行的开头和结尾,而不仅仅是整个字符串的开头和结尾。 单行模式。更改点(.)的含义,使它匹配每个字符(而不是除\n以外的所有字符)。
其他人已经建议使用HTML Agility Pack。我只是觉得你应该对为什么你的正则表达式无法工作进行解释 :)

是的,它可以工作。起初我没有提供第三个参数,它没有起作用,我以为 RegExOptions.SingleLine 是默认的,但看来 Multiline 是默认的。 - MicMit
1
单行模式和多行模式并不是相反的,无论它们的名称似乎暗示了什么。这两个选项默认都是关闭的,并且设置其中一个选项不会影响另一个选项。单行模式改变了点元字符的行为,而多行模式则改变了^$锚点的行为。 - Alan Moore
@Alan M:确实,我的回答在那方面措辞不当。我稍微更新了一下。 - Thorarin

9
请勿使用正则表达式处理标记语言 - 您需要使用专门针对此类工作构建的更好的工具。请改用Html Agility Pack。我甚至在这篇文章中找到了一个读者(名为Simon Mourier)的评论,其中包含使用Html Agility Pack从文档中删除注释的函数。请参考Html Agiliy Pack

Simon Mourier said:

This is a sample code to remove comments:

static void Main(string[] args) 
{ 
  HtmlDocument doc = new HtmlDocument(); 
  doc.Load("filewithcomments.htm"); 
  doc.Save(Console.Out); // show before 
  RemoveComments(doc.DocumentNode); 
  doc.Save(Console.Out); // show after 
} 

static void RemoveComments(HtmlNode node)
{
    if (!node.HasChildNodes)
    {
        return;
    }

    for (int i=0; i<node.ChildNodes.Count; i++)
    {
        if (node.ChildNodes[i].NodeType == HtmlNodeType.Comment)
        {
            node.ChildNodes.RemoveAt(i);
            --i;
        }
    }

    foreach (HtmlNode subNode in node.ChildNodes)
    {
        RemoveComments(subNode);
    }
}

我在其他帖子中看到了你类似的评论。一些人评论说,他们不明白为什么要使用更好的工具来偶尔进行 Web 抓取,并提取 HTML 页面上开始和结束标记之间的 hrefs。 - MicMit
1
安德鲁是正确的。除非(a)您事先知道正在使用非常受限且固定的内容集,或者(b)您不介意结果中有很多错误,否则您无法使用正则表达式解析[X][HT]ML。解析注释比解析链接更不容易出错,因为链接的格式变化更大,但仍然不可靠。 - bobince
7
代码示例不起作用。在枚举集合时,您不能修改节点。 - Andrew Harry

2
这是通过C#删除注释的谷歌搜索结果,以下是我使用HtmlAgilityPack编写的代码。
注:HtmlAgilityPack是一个开源库,用于解析HTML文档。
        HtmlDocument doc = new HtmlDocument
                           {
                               OptionFixNestedTags = true,
                               OptionOutputAsXml = true
                           };
        doc.LoadHtml(str);

        // Script comments from the document. 
        if (doc.DocumentNode != null)
        {
            HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes("//comment()");
            if (nodes != null)
            {
                foreach (HtmlNode node in from cmt in nodes
                                          where (cmt != null
                                                 && cmt.InnerText != null
                                                 && !cmt.InnerText.ToUpper().StartsWith("DOCTYPE"))
                                                 && cmt.ParentNode != null
                                          select cmt)
                {
                    node.ParentNode.RemoveChild(node);
                }
            }
        }

这段代码能够正确地去除注释,并忽略HtmlAgilityPack中被视为注释的doctype。

虽然正则表达式在受控条件下可以工作,但如果你要处理来自互联网的HTML,我建议使用HtmlAgilityPack。那里的HTML非常不可预测,而且正则表达式会出错。


-1

这个对我有效:

<!--(\n|.)*-->

但我认为您可以使用普通的XML文档来处理XML,或者使用HtmlAgilityPack来处理HTML。强烈不建议使用正则表达式解析标记。


2
你应该在乘数上放置一个非贪婪量词,即 <!--(\n|.)*?-->。此外,这个问题可以通过简单地添加 SingleLine 标志来解决,它修改了 . 以接受换行符。 - Matthew Scharley
@Matthew。是的。我同意。理论上你是正确的。但我尝试了SingleLine标志,它并没有改变结果。而且非贪婪和贪婪都可以工作。使用radsoftware.com.au/?from=RegexDesigner进行测试。 - Dmytrii Nagirniak
你永远不应该使用 (\n|.)*,因为它不精确,极其低效,需要大量回溯,并且是多余的,因为仅带有 (?s)RegexOptions.Singleline. 可以更有效地完成工作。由于使用这种不幸的模式已经报告了很多问题,请考虑删除帖子或更改解决方案。 - Wiktor Stribiżew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接