解析HTML文档:正则表达式还是LINQ?

尝试解析HTML文档并提取一些元素(文本文件的任何链接)。

当前的策略是将HTML文档加载到字符串中。 然后找到文本文件的所有链接实例。 它可以是任何文件类型,但对于这个问题,它是一个文本文件。

最终目标是拥有一个IEnumerable字符串对象列表。 这部分很简单,但解析数据是个问题。

  Blah   
Here is your first text file:
Here is your second text file:
Thanks for visiting!

最初的方法是:

  • 将字符串加载到XML文档中,并以Linq-To-Xml方式对其进行攻击。
  • 创建一个正则表达式,查找以href=开头,以.txt结尾的字符串

问题是:

  • 那个正则表达式是什么样的? 我是一个正则表达式的新手,这是我的正则表达式学习的一部分。
  • 您将使用哪种方法提取标签列表?
  • 这将是最高效的方式?
  • 哪种方法最易读/可维护?

更新:在HTML Agility Pack建议中向Matthew致敬。 它工作得很好! XPath建议也适用。 我希望我能将这两个答案都标记为“答案”,但我显然不能。 它们都是解决问题的有效方法。

这是一个使用Jeff建议的正则表达式的C#控制台应用程序。 它读取字符串很好,并且不包括任何未以.txt结尾的href。 使用给定的示例,它正确地.txt.snarg结果中包含.txt.snarg文件(在HTML字符串函数中提供)。

 using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using System.IO; namespace ParsePageLinks { class Program { static void Main(string[] args) { GetAllLinksFromStringByRegex(); } static List GetAllLinksFromStringByRegex() { string myHtmlString = BuildHtmlString(); string txtFileExp = "href=\"([^\\\"]*\\.txt)\""; List foundTextFiles = new List(); MatchCollection textFileLinkMatches = Regex.Matches(myHtmlString, txtFileExp, RegexOptions.IgnoreCase); foreach (Match m in textFileLinkMatches) { foundTextFiles.Add( m.Groups[1].ToString()); // this is your captured group } return files; } static string BuildHtmlString() { return new StringReader(@"Blah
Here is your second text file:
Thanks for visiting!
").ReadToEnd(); } } }

我会推荐正则表达式。 为什么?

  • 灵活(不区分大小写,易于添加新文件扩展名,要检查的元素等)
  • 快写
  • 快跑

只要你可以写正则表达式,正则表达式将不难阅读。

使用它作为正则表达式:

href="([^"]*\.txt)"

说明:

  • 它在文件名周围有括号,这将产生一个“捕获的组”,您可以在找到每个匹配后访问它。
  • 它必须逃脱“。” 通过使用正则表达式转义字符,反斜杠。
  • 它必须匹配除双引号之外的任何字符:[^“]直到找到它
    “.txt”

它转换为一个转义字符串,如下所示:

 string txtExp = "href=\"([^\\\"]*\\.txt)\" 

然后你可以迭代你的匹配:

 Matches txtMatches = Regex.Matches(input, exp, RegexOptions.IgnoreCase); foreach(Match m in txtMatches) { string filename = m.Groups[1]; // this is your captured group } 

都不是。 将它加载到(X / HT)MLD文档中并使用XPath,这是一种操作XML的标准方法,function非常强大。 要查看的function是SelectNodes和SelectSingleNode 。

由于您显然使用HTML(而不是XHTML),因此您应该使用HTML Agility Pack 。 大多数方法和属性都与相关的XML类相匹配。

使用XPath的示例实现:

  HtmlDocument doc = new HtmlDocument(); doc.Load(new StringReader(@" Blah   
Here is your second text file:
Here is your third text file:
Here is your fourth text file:
Thanks for visiting!
")); HtmlNode root = doc.DocumentNode; // 3 = ".txt".Length - 1. See http://stackoverflow.com/questions/402211/how-to-use-xpath-function-in-a-xpathexpression-instance-programatically HtmlNodeCollection links = root.SelectNodes("//a[@href['.txt' = substring(., string-length(.)- 3)]]"); IList fileStrings; if(links != null) { fileStrings = new List(links.Count); foreach(HtmlNode link in links) fileStrings.Add(link.GetAttributeValue("href", null)); } else fileStrings = new List(0);

另外,Matthew Flaschen的建议是DOM (例如,如果您患有X?L过敏症爆发)

它有时会得到一个糟糕的代表 – 我想因为实现有趣,并且本机COM接口有点笨拙而没有一些(次要)智能助手,但我发现它是一种强大,稳定,直观/可探索的解析方式和操纵HTML。

REGEX并不快,实际上它比.NET中的本地字符串解析更慢。 不要相信我,亲眼看看。

以上示例都不比直接转到DOM更快。

 HTMLDocument doc = wb.Document; var links = doc.Links;