【问题标题】:multiple match in regex正则表达式中的多重匹配
【发布时间】:2016-06-24 16:07:26
【问题描述】:
图案和文字在线展示https://regex101.com/r/aL5dD4/2
该模式应该找到位于代码标签之间的 span 元素的节点值。
正文如下:
<code>
<div>
<span ds = 'dsds'>12 3 ->;:4</span><span>abc</span>
</div>
</code>
正则表达式模式如下:
/(?<=<code>).*?<span[^>]*?>(.*?)(?=<\/span>.*?<\/code)/gs
我需要它来匹配两个节点值 12 3 ->;:4 和 abc。
但只找到第一个。
如何获得?
谢谢。
【问题讨论】:
标签:
regex
pcre
regex-lookarounds
【解决方案1】:
Regex 从来都不是解析 HTML/XML 的好工具。如下使用DOM:
$html=<<<EOF
<code>
<div>
<span ds = 'dsds'>12 3 ->;:4</span><span>abc</span>
</div>
</code>
EOF;
$xpath = new DOMXPath(@DOMDocument::loadHTML($html));
$nodeList = $xpath->query('//code/div/span');
$vals = array();
for($i=0; $i < $nodeList->length; $i++) {
$vals[] = $nodeList->item($i)->nodeValue;
}
print_r( $vals );
Code Demo
输出:
Array
(
[0] => 12 3 ->;:4
[1] => abc
)
【解决方案2】:
虽然我同意反对将 Regex 用于 HTML 的观点,但为了回答您的问题,消除 (?<=<code>) 背后的外观允许 Regex 也可以找到第二个匹配项。这留下了以下正则表达式:
<span[^>]*?>(.*?)(?=<\/span>.*?<\/code)
注意:这会返回两个单独的匹配项,并且不需要在元素中找到字符串。要要求匹配位于代码块中,您可以使用 @HamZa 的注释解决方案(尽管此解决方案提供 1 个匹配两个组作为字符串),它甚至可能更接近您正在寻找的内容。
【解决方案3】:
一种方法是首先使用/<code[^>]*?>(.*?)<\/code>/gs 之类的内容获取代码块,然后在这些匹配项上使用/<span[^>]*?>(.*?)<\/span>/gs。
这些“更简单”的正则表达式还可以让您在遇到问题时更轻松地进行调试。此外,这种方法从多个代码块中顺序提取所有跨度。