preg_match_all 模式中的重复模式不会导致多个 $ 匹配项

repeated pattern in preg_match_all pattern doesn't result in multiple $matches

我的脚本很简单:

<?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] 仅包含 $str 中最后出现的 \s+\d+。我期待它应该包含所有匹配项:9, 334, 23423343, 343434.

有没有什么方法可以改变我的模式,使它 returns 一个字符串的所有这些数字都可以包含任意数量的字符串?我认为这是 preg_match_all 的错误行为是否正确?我应该向 PHP 开发人员报告吗?

编辑:根据docsPREG_PATTERN_ORDER的默认标志:

Orders results so that $matches[0] is an array of full pattern matches, $matches[1] is an array of strings matched by the first parenthesized subpattern, and so on.

PCRE 将最后一次出现的事件存储在重复捕获组中,因此该行为是预期的。在这种情况下,要 return 个单独的匹配项,您需要使用 \G 令牌,如下所示:

(?:^mem:|\G(?!^))\s+\K\d+

See live demo

正则表达式细分:

  • (?: 非捕获组开始
    • ^mem: 在输入字符串的开头匹配 mem:
    • |
    • \G(?!^) 从上一场比赛结束的地方开始比赛
  • ) 非捕获组结束
  • \s+\K 匹配任何空格序列然后清除输出
  • \d+ 匹配数字

PHP代码:

preg_match_all("~(?:^mem:|\G(?!^))\s+\K\d+~", $str, $matches);