PHP preg_match:使用+或*修饰符进行的多个组匹配不会出现在结果中?

时间:2019-02-06 14:34:42

标签: php regex preg-match

如果我在PHP中这样做:

$str = "abc pqrs-1/2&3uvw xyz";
preg_match( "/([a-z]+)([^0-9a-z][0-9])+([a-z]+)/" , $str , $m );

$m中产生的匹配为:

[0] => "pqrs-1/2&3uvw"
[1] => "pqrs"
[2] => "&3"
[3] => "uvw"

请注意,([^0-9a-z][0-9])+部分应该捕获“一个非字母数字字符,然后再购买一位数”一次或多次,+修饰符在外部括号。

很明显,主题字符串$str包含3个与该模式匹配的字符串:-1/2&3,但它只记住 last 一个。

是否有办法以某种方式将它们全部捕获?

我尝试使用preg_match_all而不是preg_match,但是只有在主题字符串中 entire 正则表达式多次匹配后,才能找到多个匹配项。

要表达我的正则表达式的含义:

  1. 一个或多个字母
  2. 一个或多个:非字母数字字符,后跟数字
  3. 一个或多个字母

所以对于上面的示例字符串,我希望结果是这样的:

[0] => "pqrs-1/2&3uvw"
[1] => "pqrs"
[2] => [ "-1" , "/2" , "&3" ]
[3] => "uvw"

但是无论我如何尝试,我都无法同时给出-1/2的匹配项?

1 个答案:

答案 0 :(得分:1)

您不能将重复的子字符串与重复的捕获组匹配。相反,您需要使用两步方法来做到这一点:

  • 使用/([a-z]+)((?:[^0-9a-z][0-9])+)([a-z]+)/正则表达式与((?:[^0-9a-z][0-9])+)匹配并捕获(?:[^0-9a-z][0-9])模式的重复
  • 然后,将preg_match_all与组模式'/[^0-9a-z][0-9]/'一起使用。

PHP demo

$str = "abc pqrs-1/2&3uvw xyz";
if (preg_match('~([a-z]+)((?:[^0-9a-z][0-9])+)([a-z]+)~', $str, $matches)) {
    preg_match_all('~[^0-9a-z][0-9]~', $matches[2], $x);
    $matches[2] = $x[0];
}
print_r($matches);

输出:

Array
(
    [0] => pqrs-1/2&3uvw
    [1] => pqrs
    [2] => Array
        (
            [0] => -1
            [1] => /2
            [2] => &3
        )

    [3] => uvw
)