与preg_match_all()重复匹配

Ben*_*min 10 php regex preg-match-all preg-match

我试图让所有子串与乘数匹配:

$list = '1,2,3,4';
preg_match_all('|\d+(,\d+)*|', $list, $matches);
print_r($matches);
Run Code Online (Sandbox Code Playgroud)

此示例按预期返回上次匹配[1]:

Array
(
    [0] => Array
        (
            [0] => 1,2,3,4
        )

    [1] => Array
        (
            [0] => ,4
        )

)
Run Code Online (Sandbox Code Playgroud)

但是,我希望得到所有匹配的字符串(,\d+),以获得类似的东西:

Array
(
    [0] => ,2
    [1] => ,3
    [2] => ,4
)
Run Code Online (Sandbox Code Playgroud)

有没有办法用一个功能,如preg_match_all()

Ben*_*min 8

根据Kobi(见上述评论):

PHP不支持同一组的捕获

因此这个问题没有解决方案.


rev*_*evo 7

确实,PHP(或者更好地说 PCRE)不会存储重复捕获组的值以供以后访问(请参阅PCRE 文档):

如果重复匹配捕获子模式,则返回它匹配的字符串的最后部分。

但在大多数情况下,已知的令牌\G就可以完成这项工作。\G1) 匹配输入字符串的开头(\A当修饰符未设置时)或 2) 从上一个匹配结束的位置开始匹配^m也就是说,你必须像下面这样使用它:

preg_match_all('/^\d+|\G(?!^)(,?\d+)\K/', $list, $matches);
Run Code Online (Sandbox Code Playgroud)

在这里查看现场演示

或者如果捕获组并不重要:

preg_match_all('/\G,?\d+/', $list, $matches);
Run Code Online (Sandbox Code Playgroud)

通过它$matches可以保存这个(参见现场演示):

Array
(
    [0] => Array
        (
            [0] => 1
            [1] => ,2
            [2] => ,3
            [3] => ,4
        )

)
Run Code Online (Sandbox Code Playgroud)

注意\G:使用其他答案(例如explode()或lookbehind解决方案或只是)的好处是,您可以在导出匹配时同时preg_match_all('/,?\d+/', ...)验证输入字符串仅采用所需的格式:^\d+(,\d+)*$

preg_match_all('/(?:^(?=\d+(?:,\d+)*$)|\G(?!^),)\d+/', $list, $matches);
Run Code Online (Sandbox Code Playgroud)