【问题标题】:Regex to extract the contents of a <div> tag正则表达式提取 <div> 标记的内容
【发布时间】:2012-07-03 07:48:00
【问题描述】:

这里有点头脑僵硬,所以我希望得到一些指示,基本上我需要提取特定 div 标签的内容,是的,我知道正则表达式通常不被批准,但它是一个简单的网络没有嵌套 div 的抓取应用程序。

我正在尝试匹配这个:

    <div class="entry">
  <span class="title">Some company</span>
  <span class="description">
  <strong>Address: </strong>Some address
    <br /><strong>Telephone: </strong> 01908 12345
  </span>
</div>

简单的vb代码如下:

    Dim myMatches As MatchCollection
    Dim myRegex As New Regex("<div.*?class=""entry"".*?>.*</div>", RegexOptions.Singleline)
    Dim wc As New WebClient
    Dim html As String = wc.DownloadString("http://somewebaddress.com")
    RichTextBox1.Text = html
    myMatches = myRegex.Matches(html)
    MsgBox(html)
    'Search for all the words in a string
    Dim successfulMatch As Match
    For Each successfulMatch In myMatches
        MsgBox(successfulMatch.Groups(1).ToString)
    Next

任何帮助将不胜感激。

【问题讨论】:

  • 您使用的正则表达式有什么问题?它与您的输入相匹配。
  • 这很奇怪,它与整个页面上的任何内容都不匹配,并且那里大约有 20 个 div
  • 我知道@Tim 以比我更好的方式回答了这个问题,但是为了您将来的参考,没有第二组,所以Groups(1)(这是 base-0 索引)将总是返回一个空字符串......它应该是Groups(0)

标签: regex vb.net html


【解决方案1】:

您的正则表达式适用于您的示例。不过还是有一些改进的地方:

<div[^<>]*class="entry"[^<>]*>(?<content>.*?)</div>

[^&lt;&gt;]* 表示“匹配除尖括号外的任意数量的字符”,确保我们不会意外跳出我们所在的标签。

.*?(注意?)的意思是“匹配任意数量的字符,但只匹配尽可能少的字符”。这样可以避免页面中从第一个到最后一个 &lt;div class="entry"&gt; 标记的匹配。

但是你的正则表达式本身应该仍然匹配一些东西。也许您没有正确使用它?

我不懂 Visual Basic,所以这只是在黑暗中拍摄,但 RegexBuddy 建议采用以下方法:

Dim RegexObj As New Regex("<div[^<>]*class=""entry""[^<>]*>(?<content>.*?)</div>")
Dim MatchResult As Match = RegexObj.Match(SubjectString)
While MatchResult.Success
    ResultList.Add(MatchResult.Groups("content").Value)
    MatchResult = MatchResult.NextMatch()
End While

我建议不要采取比这更进一步的正则表达式方法。如果你坚持,你最终会得到一个像下面这样的怪物正则表达式,它只有在div 的内容形式不变的情况下才有效:

<div[^<>]*class="entry"[^<>]*>\s*
<span[^<>]*class="title"[^<>]*>\s*
(?<title>.*?)
\s*</span>\s*
<span[^<>]*class="description"[^<>]*>\s*
<strong>\s*Address:\s*</strong>\s*
(?<address>.*?)
\s*<strong>\s*Telephone:\s*</strong>\s*
(?<phone>.*?)
\s*</span>\s*</div>

或者(看看 VB.NET 中多行字符串的乐趣):

Dim RegexObj As New Regex(
    "<div[^<>]*class=""entry""[^<>]*>\s*" & chr(10) & _
    "<span[^<>]*class=""title""[^<>]*>\s*" & chr(10) & _
    "(?<title>.*?)" & chr(10) & _
    "\s*</span>\s*" & chr(10) & _
    "<span[^<>]*class=""description""[^<>]*>\s*" & chr(10) & _
    "<strong>\s*Address:\s*</strong>\s*" & chr(10) & _
    "(?<address>.*?)" & chr(10) & _
    "\s*<strong>\s*Telephone:\s*</strong>\s*" & chr(10) & _
    "(?<phone>.*?)" & chr(10) & _
    "\s*</span>\s*</div>", 
    RegexOptions.Singleline Or RegexOptions.IgnorePatternWhitespace)

(当然,现在您需要将结果存储为MatchResult.Groups("title") 等...)

【讨论】:

  • 你我的朋友是明星!如果我想获取该 div 中的每个元素,即跨度类值 id 只需在 div 标签的关闭 > 之后执行 .*?]*class="title"?
  • 我相信原始代码没有被提取的原因是因为它应该是Groups(0)而不是Groups(1)
  • @MarcFielding:我已经编辑了我的答案:命名捕获组(?&lt;content&gt;.*?) 将捕获divs 之间的所有内容。
  • @freefaller 是的,我注意到我实际上正在使用一个断点并检查匹配集合以查看它是否在拾取任何东西
  • 我会将 tim 的答案标记为正确答案,尽管我不介意知道如何提取每个 span 的值,因此如果您觉得 Tim 精力充沛,我会提取公司名称、地址和电话号码?
【解决方案2】:

尝试使用RegexOptions.Multiline 而不是RegexOptions.Singleline

感谢@Tim 指出上述方法不起作用……我的错。

@Tim 的答案很好,应该是公认的答案,但是阻止您的代码工作的额外部分是 Group(1) 没有第二组返回。

改变...

MsgBox(successfulMatch.Groups(1).ToString)

到...

MsgBox(successfulMatch.Groups(0).ToString)

【讨论】:

    【解决方案3】:

    用这个

    <div.*?class=""entry"".*?>(?<divBody>.*)</div>
    

    并获得名为 divBody

    的组

    但请注意,如果字符串包含其他节点 div,这将不起作用(并且似乎无法通过正则表达式解决此问题)。对于您的解决方案 xslt 可能有用。

    【讨论】:

    • 小心,这匹配 all div 标签(不仅仅是那些带有class="entry" 的标签),它匹配从第一个开头&lt;div&gt; 到最后一个结尾@ 的所有内容987654324@.
    • Used (?.*)
      - 不像蒂姆所说的那样工作,它应该匹配所有东西,但显然没有't
    【解决方案4】:

    真是好文章。请参阅以下来自 eclipse 的附加结果

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-28
      • 2015-12-10
      • 1970-01-01
      • 1970-01-01
      • 2017-06-26
      • 2014-10-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多