我的脚本很简单:
<?php
$str = "mem: 9 334 23423343 3433434";
$num_matches = preg_match_all("/^mem:(\s+\d+)+$/", $str, $matches);
if (!$num_matches) {
throw new Exception("no match");
}
echo "$num_matches matches\n";
var_dump($matches);
我期望模式(\s+\d+)+
应该与$str
中的所有数字匹配,但是由于某些原因,输出仅显示最后一个匹配项:
1 matches
array(2) {
[0] =>
array(1) {
[0] =>
string(27) "mem: 9 334 23423343 3433434"
}
[1] =>
array(1) {
[0] =>
string(8) " 3433434"
}
}
如您所见,$matches[1]
仅包含\s+\d+
中最近出现的$str
。我期望它包含所有匹配项:9, 334, 23423343, 343434
。
是否有某种方法可以更改我的模式,以便它为可能包含任意数量的字符串的字符串返回所有这些数字?我是否认为preg_match_all是不正确的行为?我应该将其报告给PHP开发人员吗?
编辑:根据docs,默认标志为 PREG_PATTERN_ORDER :
对结果进行排序,以使$ matches [0]是完整模式匹配的数组,$ matches [1]是由第一个带括号的子模式匹配的字符串的数组,依此类推。
答案 0 :(得分:1)
PCRE将最后一次出现的事件存储在重复的捕获组中,因此可以预期该行为。在这种情况下,要返回单个匹配项,您需要使用\G
令牌,如下所示:
(?:^mem:|\G(?!^))\s+\K\d+
正则表达式细目:
(?:
非捕获组的开始
^mem:
在输入字符串的开头匹配mem:
|
或\G(?!^)
从上一场比赛结束的地方开始比赛)
非捕获组的结尾\s+\K
匹配任何空白序列,然后清除输出\d+
匹配数字PHP代码:
preg_match_all("~(?:^mem:|\G(?!^))\s+\K\d+~", $str, $matches);