正则表达式匹配可选子组的一部分

时间:2012-04-09 21:31:19

标签: php regex

我正试图从网站上抓取多个事件。

的常规格式
... EVENT TITLE & LINK ... START DATE ... END DATE ... <span class="location">LOCATION</span> ...

其中“...”是一些带有样式信息和换行符的html标签。我想从这些事件字符串中提取LINK,START DATE,END DATE和LOCATION。由于周围的html代码“...”的格式是完全规则的,抓取这四个信息很容易:我匹配周围的标签并提取我想要的部分,例如:

'|...<abbr class="dtstart">(.{10}).*?</abbr>...|s'

其中“(。{10})”是开始日期。

问题在于LOCATION,因为某些事件列出了一个位置,其他事件列出时没有,因此在某些事件中,span标记&lt; span class =“location”&gt; LOCATION&lt; / span&gt;存在,在其他情况下它只是缺失。

所以我的问题是:

我如何匹配LOCATION?

如果我尝试

preg_match_all('|...<span class="location">(.+?)</span>...|s', $contents, $matches, PREG_SET_ORDER);

在没有位置的事件上,它与该事件不匹配(但我得到了一个有一个事件的LOCATION)。另一方面,如果我尝试

preg_match_all('|...(?:<span class="location">(.+?)</span>)...|s', $contents, $matches, PREG_SET_ORDER);

在任何事件中,该代码都匹配所有事件,但LOCATION - 即使它存在 - 也不属于我的$ matches。

那么如何匹配常规但可选的子字符串的不规则部分呢?

谢谢!

编辑(作为zigdon问题的答案):

问题是LOCATION必须与其他事件数据匹配。想象一下这就是我想要的结果:“正义大联盟(链接到网站),4月7日到4月10日,柏林”和“在线教程(链接到网站,5月9日)。”第二个活动没有位置,但第一个事件的位置必须与标题,链接和日期匹配。这是我想要从中获取事件的页面的链接,您可以查看源代码以了解问题:{ {3}} - 目前我用

抓住了这些事件
preg_match_all('|<dt class="vevent">\s*?<span class="summary">\s*?(<a href=".+?</a>)\s*?</span>\s*?<span class="documentByLine">\s*?<span>(?:von )?<abbr class="dtstart" title=".{0,30}">(.{10}).{0,6}</abbr>.{5,100}<abbr class="dtend" title=".+?">(.{0,10}).{5,6}</abbr></span>\s*?(?:<span>— <span class="location">(.*?)</span>,</span>)?\s*?</span>\s*?</dt>|', $contents, $matches, PREG_SET_ORDER);

这很有效,但我对它不满意,因为正如答案中所提到的,“野性代码”(来自不属于我自己的网站)可能会在标签之间发生任何事情。我更喜欢一种只匹配事件部分的直接周围的解决方案,并留下非常开放的内容,即“。*?| s”。

1 个答案:

答案 0 :(得分:1)

使用正则表达式来解析HTML(或任何实际的标记)通常是一个非常糟糕的主意。大多数语言提供了一个实际解析HTML的库,允许您获取所需的特定元素,而无需尝试将标记与正则表达式匹配。也许,因为看起来你可能正在使用PHP,你可以看看这样的东西? http://simplehtmldom.sourceforge.net/

另见RegEx match open tags except XHTML self-contained tags