在PHP中使用单个preg_match_all查找多个模式

4
使用PHP和preg_match_all,我正在尝试获取以下标签(以及标签之间的所有HTML内容):

<p>paragraph text</p>
don't take this
<ul><li>item 1</li><li>item 2</li></ul>
don't take this
<table><tr><td>table content</td></tr></table>

我可以很好地获取其中一个:

preg_match_all("(<p>(.*)</p>)siU", $content, $matches, PREG_SET_ORDER);

有没有一种方法可以获取所有的
<p></p> <ul></ul> <table></table>

您是否需要使用单个 preg_match_all 函数来提取内容?我需要按照它们被找到的顺序将它们输出,以便在 echo 时使内容更有意义。

如果我在上面的内容中执行 preg_match_all,然后遍历 $matches 数组,它会依次输出:

<p>paragraph text</p>
<ul><li>item 1</li><li>item 2</li></ul>
<table><tr><td>table content</td></tr></table>

2
使用XML解析器。 - eykanal
@mario:实际上有点两者兼而有之,只是夸张了一点。重要的是:“正则表达式是一种工具,不足以理解HTML所使用的结构。HTML不是一种正则语言,因此不能被正则表达式解析。” - netcoder
你应该使用一个XML解析器。(没错,继续标记这个评论) - user1228
不要使用正则表达式来解析HTML。请使用适当的HTML解析模块。您无法可靠地使用正则表达式解析HTML,而且在后续过程中会遇到悲伤和挫折。一旦HTML与您的预期不同,您的代码将被破坏。请参阅http://htmlparsing.com/php,了解如何使用已经编写、测试和调试的PHP模块正确解析HTML的示例。 - Andy Lester
4个回答

11

使用|来匹配一组字符串中的一个:p|ul|table

使用反向引用来匹配相应的闭合标签:\\2,因为组(pl|ul|table)包含第二个开括号。

把所有东西都放在一起:

preg_match_all("(<(p|ul|table)>(.*)</\\2>)siU", $content, $matches, PREG_SET_ORDER);

如果您的输入HTML遵循非常严格的结构,此方法才能正常工作。标签中不能有空格,也不能有任何属性。如果存在嵌套,则此方法也会失败。建议考虑使用HTML解析器来完成更好的工作。


4
这对我有用。
preg_match_all("#<\b(p|ul|table)\b[^>]*>(.*?)</\b(p|ul|table)\b>#si", $content, $matches)

1
如果您要使用DOM解析器,而且您应该这样做,那么以下是如何操作的。一位贡献者发布了一个有用的函数,用于获取DOMNode的innerHTML,我将在以下示例中使用它:
$dom = new DOMDocument;
$dom->loadHTML($html);

$p = $dom->getElementsByTagName('p')->item(0); // first <p> node
$ul = $dom->getElementsByTagName('ul')->item(0); // first <ul> node
$table = $dom->getElementsByTagName('table')->item(0); // first <table> node

echo DOMinnerHTML($p);
echo DOMinnerHTML($ul);
echo DOMinnerHTML($table);

0

虽然可以使用正则表达式来完成,但是您可以使用更简单的HTML解析工具包来简化任务。例如,使用phpQuery或者QueryPath就像这样简单:

qp($html)->find("p, ul, table")->text();   // or loop over them

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接