Regex optional groups


Regex optional groups

我想在<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代码。它只检测一个组,并将所有内容放入其中。

这个神奇的词要么是'转义'要么是'分隔符',继续读。

第一个正则表达式:
<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>)?/';

以上假设您将regex放在两个/"分隔符"字符之间(出于传统习惯)。

为了更深入地了解这个问题,我们应该注意到,在php中,正则表达式的第一个和最后一个字符通常是一个"分隔符",因此可以在末尾添加修饰符(如不区分大小写等)。

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

这里是一个工作的(基于web的)示例,使用#作为分隔符(只是因为我们可以)。

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

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

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