正则表达式没有明显的原因匹配

时间:2010-07-03 11:24:40

标签: php regex pcre

考虑以下两个正常表达式片段和匹配的虚拟HTML:

显然,我只能发布一个链接,直到获得更多声望,因此下面的链接包含我在上面引用的三个链接:

http://pastebin.com/Qj1uxfdk

两个片段之间的区别,如果有人想知道的话,在片段的一半左右被移除(((.{2,20}?), (.{2,20}?))?)

第一个代码段与文本不匹配,但第二个代码段与文本不匹配,我无法弄清楚原因。我尝试放置一个虚拟表达式,它应该匹配任何地方(例如(.{1})?)并且仍然无法匹配它,但当我删除它时,它会突然再次匹配。

在过去的4个小时里,我一直在用这种愚蠢的表情辛苦劳作,而我的智慧结束了。有人可以帮忙吗?

3 个答案:

答案 0 :(得分:0)

我非常抱歉,我知道这个答案不会因为各种原因而受到任何人的赞赏,但无论如何,我觉得我必须这样说。

在我看来,你可能正在使用错误的工具。我建议你使用一个真正的解析器来解析(x)html / xml。我认为,html包含的细微之处远远超过你现实能够捕捉到的正则表达式。我,我自己,已经有很长时间没有编写任何PHP了,但我确信它有必要的工具来为你解析(maybe this?)。

当然,自己做所有事情是令人兴奋的,但是利用已经完成(和测试)的事情更为实际。

我希望你能牢记这一点。

PS:是的,我知道,通常的“不要用正则表达式解析xml”语句非常陈腐/平庸,但它并不能阻止它在大多数情况下都是真的。

答案 1 :(得分:0)

因为您似乎知道在解析HTML时RegEx不是真的,所以 为什么你还试着......?

例如,DOM并不像你想象的那么难;
获取HTML中所有td的基本示例:     

$html = <<< EOL
<tr><td nowrap class="border_on_rbl"><a href="employee_view.html?employee_id=1337">bloblaw</td><td nowrap class="border_on_rb">Loblaw, Bob</b></td><td nowrap class="border_on_rb">Lawyer</td>
<td nowrap class="border_on_rb">Legal</td>
<td nowrap class="border_on_rb">person4</td><td nowrap class="border_on_rb"></td><td nowrap class="border_on_rb">Bluth, Maeby</td><td nowrap class="border_on_rb"><a href=mailto:bloblaw@theplanet.com>bloblaw@theplanet.com</a></td><td nowrap class="border_on_rb">555.555.5555</td><td nowrap class="border_on_rb">1337</td></tr>
EOL;

libxml_use_internal_errors(true);
$dom = DOMDocument::loadHTML($html);

$tds = $dom->getElementsByTagName('td');
foreach ($tds as $td) {
    echo $td->nodeValue.'<br>';
}

?>

花点时间阅读关于DOM的手册/一些教程/文章/ ..你将永远不会(RegEx)解析(不仅仅是)HTML ..

答案 2 :(得分:-1)

重写它比调试它要容易一些,所以这是我的方法:

preg_match_all(
    '%<tr>[^<]*
      <td[^>]*><a.*?employee_id=(\d*).*?>(\w*)\s*.*?&nbsp;</td>[^<]*
      <td[^>]*>(\w*),\s*(\w*).*?&nbsp;</td>[^<]*
      <td[^>]*>(\w*).*?&nbsp;</td>[^<]*
      <td[^>]*>(\w*).*?&nbsp;</td>[^<]*
      <td[^>]*>(\w*).*?&nbsp;</td>[^<]*
      <td[^>]*>(\w*).*?&nbsp;</td>[^<]*
      <td[^>]*>(\w*).*?&nbsp;</td>[^<]*
      <td[^>]*><a[^>]*>(.*?)</a>.*?&nbsp;</td>[^<]*
      <td[^>]*>(\d{3}\.\d{3}\.\d{4}).*?&nbsp;</td>[^<]*
      <td[^>]*>(\w*).*?&nbsp;</td>[^<]*
    </tr>%sx', 
    $subject, $result, PREG_SET_ORDER);

它适用于您的示例,如果您喜欢或多或少的验证,您可以调整它。