PCRE无法存储重复捕获组的不同内容。当组重复时,以前的内容将被当前内容覆盖,以此类推。
一种解决方法包括使用
preg_match_all
和
\G
在上一次匹配后匹配下一个位置的锚点(默认情况下,它也匹配字符串的开头)。
preg_match_all('~(?:\G(?!\A)|<!-- @@include)\s+(try|default|file)="(.*?)"~', $str, $matches);
这种模式的想法是在第二个分支上取得成功
<!-- @@include
对于第一个匹配,然后与第一个分支
\G(?!\A)
对于所有其他连续比赛。当零件
\s+(try|default|file)="(.*?)"
失败,连续性被破坏,正则表达式引擎必须找到下一个
<!-- @@包括
继续。
如果您想知道第二个分支何时成功,只需在第二个分支中放置一个捕获组:
$result = [];
if ( preg_match_all('~(?:\G(?!\A)|<!-- (@)@include)\s+(try|default|file)="(.*?)"~', $str, $matches, PREG_SET_ORDER) ) {
foreach ($matches as $m) {
if ( !empty($m[1]) ) { // test which branch succeeds
if ( isset($temp) )
$result[] = $temp;
$temp=[];
}
$temp[$m[2]] = $m[3];
}
}
if ( isset($temp) )
$result[] = $temp;
demo
要获得更灵活且能够处理未知密钥的功能,可以使用两个
preg\u match\u全部
:
$result = [];
if ( preg_match_all('~<!-- @@include\s+\K\w+=".*?"(?:\s+\w+=".*?")*~', $str, $matches) ) {
foreach ($matches[0] as $params) {
if ( preg_match_all('~(\w+)="(.*?)"~', $params, $keyvals) )
$result[] = array_combine($keyvals[1], $keyvals[2]);
}
}
print_r($result);
demo
请注意,最后一个解决方案可以更有效地处理大型字符串,特别是因为第一个模式不是以交替方式开始,而是以文本字符串开始(在这种情况下,pcre regex引擎能够优化研究)。第二种模式只需要处理短字符串,所以这不是问题。