解析HTML-在这种情况下,正则表达式是唯一的选项


Parsing HTML - is regex the only option in this case?

用户将提供HTML,它可能是有效的,也可能是无效的(格式错误)。我需要能够确定以下内容:

  1. 正文中有样式标签吗
  2. 是否有一个div具有使用宽度或背景图像的style属性

我尝试过使用DOMDocument类,但它只能使用xPath执行1而不能执行2。

我也尝试过simple_html_dom,它只能做1而不能做2。

你认为我只使用正则表达式是个好主意吗?还是有什么我没有想到的?

Regex是NEVER(再次:NEVER!)解析HTML的解决方案!

Regex可用于第3类乔姆斯基语言(常规语言)
然而,HTML是一种类型2的乔姆斯基语言(上下文无关语言)。

如果仍有疑问:http://en.wikipedia.org/wiki/Chomsky_hierarchy#The_hierarchy

为了安全地使用类型2语言,您需要一个上下文无关的语言解析器。您可能想要尝试LL解析器或递归下降解析器,例如


话虽如此:

bodystyle:匹配

<body's+[^>]*style's*='s*["'].*?[^"']*?["'][^>]*>

style:中匹配divwidth|background-image

<div's+[^>]*style's*='s*["'][^"']*?(width|background-image)[^"']*?["'][^>]*>

它们都错误地匹配所说的标签,如果被注释掉(这就是为什么我说不可能)。

XPath可以同时执行(1)和(2):

测试正文中是否有样式标签:

//body//style

使用widthbackground-image:测试是否存在具有样式属性的div

//div[contains(@style,'width:') or contains(@style,'background-image:')]

而且,正如您在评论中所好奇的那样,查看样式标签是否包含a:hoverfont-size:

//style[contains(text(),'a:hover') or contains(text(),'font-size:')]

您可以使用Tidy清理HTML,然后将其解析为XML。然后可以很容易地使用xpath来查找节点。试试这样的东西:

$tidyConfig = array(
    "add-xml-decl" => true,
    "output-xml" => true,
    "numeric-entities" => true
);
$tidy = new tidy();
$tidy->parseString($html, $tidyConfig, "utf8");
$tidy->cleanRepair();
$xml = new SimpleXMLElement($tidy);
$matches = $xml->xpath('style');

至于解析样式属性以查找特定的选择器,我认为您必须手动进行。如果您愿意,可以使用CSS解析器。

用正则表达式解析HTML是一个好主意。然而,任何优秀的HTML解析器都能够找到所有带有style标记的div,一旦完成了这些操作,regex就可以用于解析样式属性。

然而,复杂(但有效)的CSS仍然有可能破坏大多数正则表达式,因此真正持久的东西是HTML解析器与CSS解析器相结合。不过,这可能有些过头了;像'bwidth's*:'s*('w+)这样的正则表达式很可能会捕获任何width值,除非有人试图欺骗它

编辑:

一个好的HTML解析器不会阻塞任何不会阻塞浏览器的东西。我不再是一个PHP爱好者,但我听说了一些关于HTML净化器的好消息。