【问题标题】:repeated pattern in preg_match_all pattern doesn't result in multiple $matchespreg_match_all 模式中的重复模式不会导致多个 $matches
【发布时间】:2019-07-03 03:28:45
【问题描述】:

我的脚本很简单:

<?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

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

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

排序结果使得 $matches[0] 是一个完整模式匹配的数组,$matches[1] 是一个由第一个带括号的子模式匹配的字符串数组,依此类推。

【问题讨论】:

  • "mem:" 是匹配字符串的一部分,因此只有包含它的内容才是匹配项。您只有一个包含“mem:”的字符串
  • @PatrickQ 我的帖子输出错误,所以我编辑了它。是的,“mem”是 whole 模式的一部分,但它不是括号的一部分。 $matches[1] 应该包含第一个括号的所有匹配项——它只有最后一个匹配项。
  • 这个问题可能会有所帮助:Split camelCase word into words with php preg_match

标签: php regex preg-match-all


【解决方案1】:

PCRE 将最后一次出现存储在重复捕获组中,因此行为是预期的。在这种情况下,要返回单个匹配项,您需要使用 \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);

【讨论】:

  • 那是一些严肃的正则表达式功夫。 PHP 的 preg 函数当然是从 PCRE 派生的,你有没有关于“PCRE 将最后一次出现在重复捕获组中”语句的文档链接?那将是锦上添花。
  • 阅读on here如果重复匹配捕获子模式,则返回匹配的字符串的最后一部分。
猜你喜欢
  • 2013-05-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-03
  • 1970-01-01
相关资源
最近更新 更多