正则表达式(正则表达式)到解析HTML段

时间:2011-01-18 19:57:11

标签: html regex parsing asp-classic vbscript

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

原始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文档中还有其他<p>...</p>个标记,不得触及。我只想在<p>...</p><td>内替换<th>

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

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>

任何想法(除了不用正则表达式做这个,哈哈)?

谢谢!

3 个答案:

答案 0 :(得分:0)

正则表达式不适合像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
}

答案 1 :(得分:0)

这是你的问题:

使用RegEx的一次拍摄必须有一些方法。

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

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

答案 2 :(得分:0)

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

可能不是最快的方式,也不是最好的方式,但它确实起到了作用。这是否有助于其他有类似问题的人,我不知道,但我认为我会抛弃这段代码以防万一,无论如何。