【问题标题】:Regular Expression (regex) to Parse HTML Segment用于解析 HTML 段的正则表达式 (regex)
【发布时间】:2011-06-11 08:01:39
【问题描述】:

我目前正在尝试提出一个正则表达式,它将解析出如下内容:

原始 HTML:

<td align="center"><p>line 1</p><p>line 2</p><p>line 3</p></td>

预期的 HTML:

<td align="center">line 1<br />line 2<br />line 3</td>

请注意,整个 HTML 文档中还有其他 &lt;p&gt;...&lt;/p&gt; 标记不能被触及。我只想在 &lt;td&gt;&lt;th&gt; 中替换 &lt;p&gt;...&lt;/p&gt;

我还需要一个正则表达式来扭转这个过程。请注意,这些正则表达式必须在 VB/VBScript/Classic ASP 中工作,所以虽然我可以使用前瞻(我认为这是这里的关键),但我不能使用后瞻。我尝试过的一些正则表达式是:

1. <td[^>]*>(<p>.+<\/p>)<\/td>
2. <td[^>]*>(<p>.+<\/p>)+?<\/td>
3. <td[^>]*><p>(?:(.+?)<\/p><p>(.+))+<\/p><\/td>
4. <td[^>]*>(<p>(?:(?!<\/p>)).*<\/p>)+?<\/td>
5. <td[^>]*>(?:<p>(.+?)<\/p>)*(?:<p>(.+)<\/p>)<\/td>
6. <td[^>]*>(?:<p>(.+?)<\/p>)(?:<p>(.+)<\/p>)*(?:<p>(.+)<\/p>)<\/td>

我可以“作弊”并拉出整行然后手动解析它,通常是标准的 VB 字符串操作函数,但这绝对不是最优雅的方式,也不是最快的方式。必须有某种方法可以使用 RegEx 一次性完成。

最后我想带...

<td align="center"><p><span style="color:#ff0000;"><strong>line 1</strong></span></p><p>line 2</p><p>line 3</p></td>

...把它变成

<td align="center"><span style="color:#ff0000;"><strong>line 1</strong></span><br />line 2<br />line 3</td>

有什么想法(除了不使用正则表达式,哈哈)?

谢谢!

【问题讨论】:

  • 您是否想过使用 HTML 解析器并对其应用一些 DOM 操作?
  • @Hank,该链接对那些还不明白 RegExes 为什么无法解析 HTML 的人没有帮助。
  • @Dour 这是我投票关闭时创建的自动评论,确实如此。有至少十几个其他骗子解释了为什么这是不可能的和一个坏主意,如果您希望关闭另一个骗子,所有这些都很容易找到。我选择这个是希望有趣的写作足以说服 OP,或者可能是成千上万的赞成票。我之前的所有努力似乎都没有效果。
  • 我已经阅读了很多,也许是几十个关于此的其他问题、答案和 cmets。大多数(如果不是全部)使用正则表达式和 HTML 来解释问题,然而,更多的人每天都使用正则表达式来解析 HTML。我找不到我的例子,这就是我写这个问题的原因。如果我的具体情况不能使用单个正则表达式(甚至几个)来完成,那很不幸,但不是世界末日。我将不得不求助于其他手段。其他人可能对高级正则表达式有更多经验,并且可能想出了一个解决方法,因此提出了这个问题。

标签: html regex parsing asp-classic vbscript


【解决方案1】:

ASP 和 IIS,更具体地说,确实支持 ISAPI 过滤器,但是,我不想或不得不求助于它。 HTML 段只是一个字符串,而不是 DOM 树的一部分(尽管如果需要我可以将它转换为一个)。

最终,这是我解决问题的方法,因为直接的正则表达式显然无法满足我的要求:

RE3.Pattern = "<td[^>]*><p>.+?<\/p><\/td>"
Set Matches = RE3.Execute(it)
If Matches.Count > 0 Then
   RE3.Pattern = "<p[^>]*>"
   For Each Match In Matches
      itxt_tmp = Replace(Replace(RE3.Replace(Match.Value,""),"</p>","<br />"),"<br /></td>","</td>")
      it = Replace(it,Match.Value,itxt_tmp)
   Next
End If
Set Matches = Nothing

然后回到原来的:

RE.Pattern = "<td[^>]*>.+?<\/td>"
Set Matches = RE.Execute(itxt)
If Matches.Count > 0 Then
   For Each Match In Matches
      If InStr(1,Match.Value,"<br />") > 1 Then
         RE.Pattern = "<td([^>]*)>"
         itxt_tmp = RE.Replace(Replace(Replace(Match.Value,"<br />","</p><p>"),"</td>","</p></td>"),"<td$1><p>")
         itxt = Replace(itxt,Match.Value,itxt_tmp)
      End If
   Next
End If
Set Matches = Nothing

可能不是最快的方法,也不是最好的方法,但它可以完成工作。我不知道这是否有助于其他有类似问题的人,但我想我会把这段代码扔出去以防万一。

【讨论】:

    【解决方案2】:

    这是你的问题:

    必须有某种方法可以使用 RegEx 一次性完成。

    这是假的,没有办法。这在数学上是不可能的。正则表达式,即使是具有前瞻功能的表达式,也无法保持解析 HTML 表达式所需的状态。

    您必须使用 HTML 解析器。已经写了很多,如果您指定您的目标环境,我们可以帮助您选择一个。例如,在 .Net 中,HTML Agility Pack 很好。

    【讨论】:

    • 不幸的是,此页面使用的是 Classic ASP,而不是 .NET(...是的,我知道),所以我不能轻易使用任何 .NET 插件。
    • @Zycon,经典 ASP 是否支持 ISAPI 过滤器?您可以编写一个过滤器,在 ASP 生成页面后使用 HTML 解析器进行翻译。
    【解决方案3】:

    正则表达式不适用于 HTML 等不规则语言。您最好使用适当的 HTML 解析器。

    你可以使用PHP’s DOM library:

    $doc = new DOMDocument();
    $doc->loadHTML($code);
    $xpath = new DOMXpath($doc);
    forach ($xpath->query('//td/p') as $i => $elem) {  // find all P elements that are a child of a TD
        if ($i != 0) {                                  // add BR for any P except the first
            $elem->parentNode->insertBefore($doc->createElement('br'), $elem);
        }
        foreach ($elem->childNodes as $nodes) {        // move contents out of P
            $elem->parentNode->insertBefore($node, $elem);
        }
        $elem->parentNode->removeChild($elem);         // remove empty P
    }
    

    【讨论】:

      猜你喜欢
      • 2020-03-14
      • 2014-05-16
      • 2010-09-08
      • 1970-01-01
      • 2014-06-08
      • 2010-09-21
      • 2016-09-23
      相关资源
      最近更新 更多