正则表达式可选组

时间:2013-04-30 22:35:52

标签: php regex

我想在<p></p>之间捕获最多四组文字。我可以使用以下正则表达式来做到这一点: <h5>Trivia<\/h5><p>(.*)<\/p><p>(.*)<\/p><p>(.*)<\/p><p>(.*)<\/p>

要匹配的文字:

<h5>Trivia</h5><p>Was discovered by a freelance photographer while sunbathing on Bournemouth Beach in August 2003.</p><p>Supports Southampton FC.</p><p>She has 11 GCSEs and 2 'A' Levels.</p><p>Listens to soul, R&amp;B, <a href="/name/nm0005567/">Stevie Wonder</a>, <a href="/name/nm0291349/">Aretha Franklin</a>, <a href="/name/nm0713378/">Usher Raymond</a>, <a href="/name/nm0001391/">Michael Jackson</a> and <a href="/name/nm0584117/">George Michael</a>.</p>

输出四行文字。如果有更多琐事项目或<p>次出现,它也可以按预期工作。

但如果少于4个琐事项目或<p>组,则不会输出任何内容,因为它找不到第四组。如何使该组可选?

我已经尝试过:<h5>Trivia<\/h5><p>(.*?)<\/p>(?:<p>(.*?)<\/p>)?(?:<p>(.*?)<\/p>)?(?:<p>(.*?)<\/p>)?(?:<p>(.*?)<\/p>)?并根据http://gskinner.com/RegExr/工作,但如果我把它放在PHP代码中则不起作用。它只检测一个组并将所有内容放入其中。

2 个答案:

答案 0 :(得分:1)

您可以使用问号使每个<p>...</p>成为可选项:

$pattern = '~<h5>Trivia</h5>(?:<p>(.*?)</p>)?(?:<p>(.*?)</p>)?(?:<p>(.*?)</p>)?(?:<p>(.*?)</p>)?~';

使用Dom也是一个不错的选择。

答案 1 :(得分:1)

这个神奇的词要么是“逃避”,要么是“分隔符”,请继续阅读。

第一个正则表达式:
<h5>Trivia<\/h5><p>(.*)<\/p><p>(.*)<\/p><p>(.*)<\/p><p>(.*)<\/p>
之所以有效,是因为您将/等标记中的</h5>个字符转义为<\/h5>

但是在你的第二个正则表达式中(正确地将每个段落包含在一个可选的非捕获组中,获取1到5个段落):
<h5>Trivia</h5><p>(.*?)</p>(?:<p>(.*?)</p>)?(?:<p>(.*?)</p>)?(?:<p>(.*?)</p>)?(?:<p>(.*?)</p>)?
你忘了逃避那些/个字符 那应该是:
$pattern = '/<h5>Trivia<\/h5><p>(.*?)<\/p>(?:<p>(.*?)<\/p>)?(?:<p>(.*?)<\/p>)?(?:<p>(.*?)<\/p>)?(?:<p>(.*?)<\/p>)?/';

以上假设您将正则表达式置于两个/“分隔符”字符之间(超出常规习惯)。

要深入潜入兔洞,应该注意到在php中,正则表达式的第一个和最后一个字符通常是“delimiter”,因此最后可以添加修饰符(如不区分大小写等。)

因此,您也可以使用~字符(或#等)作为分隔符,而不是转义正则表达式。
因此,您也可以使用您发布和封装的相同(第二个)正则表达式,例如: $pattern = '~<h5>Trivia</h5><p>(.*?)</p>(?:<p>(.*?)</p>)?(?:<p>(.*?)</p>)?(?:<p>(.*?)</p>)?(?:<p>(.*?)</p>)?~';

这是一个有效的(基于网络的)example,使用#作为分隔符(只是因为我们可以)。