Php 使用preg_match_all()获取重复匹配

Php 使用preg_match_all()获取重复匹配,php,regex,preg-match,preg-match-all,Php,Regex,Preg Match,Preg Match All,我正在尝试将所有子字符串与乘数匹配: $list = '1,2,3,4'; preg_match_all('|\d+(,\d+)*|', $list, $matches); print_r($matches); 如预期,此示例返回[1]中的最后一个匹配项: Array ( [0] => Array ( [0] => 1,2,3,4 ) [1] => Array (

我正在尝试将所有子字符串与乘数匹配:

$list = '1,2,3,4';
preg_match_all('|\d+(,\d+)*|', $list, $matches);
print_r($matches);
如预期,此示例返回
[1]
中的最后一个匹配项:

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

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

)
但是,我希望获得所有与
(,\d+
)匹配的字符串,以获得如下内容:

Array
(
    [0] => ,2
    [1] => ,3
    [2] => ,4
)
有没有一种方法可以通过单个函数来实现这一点,例如
preg\u match\u all()

为什么不:

$ar = explode(',', $list);
print_r($ar);
根据(见上述评论):

PHP不支持同一组的捕获


因此,这个问题没有解决办法。

只有在模式中没有使用要拆分的字符来匹配自身时,才能选择拆分。 我遇到过这样一种情况,一个格式错误的逗号分隔行必须被解析成许多已知选项中的任何一个

i、 e.选项“1,2”、“2”、“2,3” 主题“1,2,3”

在“,”上拆分将导致“1”、“2”和“3”;其中只有一个('2')是有效匹配项,这是因为分隔符也是选项的一部分

天真的正则表达式类似于“~^(1,2 | 2,3)(?:,(1,2 | 2,3))*$~i”,但这遇到了相同的群捕获问题

我的“解决方案”是只需扩展正则表达式以匹配可能的最大匹配数: "(1,2 | 2,3)(1,2 | 2,3)(1,2 | 2,3))(1,2 | 2,3))$~i" (如果有更多选项可用,只需重复“(?:,(1,2 | 2,3))?”位即可。 这确实会导致“未使用”匹配的空字符串结果

它不是最干净的解决方案,但在您必须处理格式不正确的输入数据时可以使用。

来自:

重复捕获子模式时,捕获的值是与最终迭代匹配的子字符串

同样类似的线程:

使用是完成工作的一种方法:

$list = '1,2,3,4';
preg_match_all('|(?<=\d),\d+|', $list, $matches);
print_r($matches);
PHP(或者更好的说法是PCRE)确实不会存储重复捕获组的值以供以后访问(请参阅):

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

但在大多数情况下,已知标记
\G
会执行此任务。
\G
1)匹配输入字符串的开头(如
\A
^
m
修饰符未设置时),或2)从上一个匹配结束处开始匹配。也就是说,您必须按照以下方式使用它:

preg_match_all('/^\d+|\G(?!^)(,?\d+)\K/', $list, $matches);

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

preg_match_all('/\G,?\d+/', $list, $matches);
通过它,
$matches
将保存此信息(请参阅):

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

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

不同的语言,但答案相同:你不能,但你可以通过
@Kobi轻松地拆分。谢谢你的链接。从他们所说的,有些语言有解决方案,对PHP有希望吗?或者这是一个明确的答案吗?
[0]=>,2
在PHP中是不可能的。
,2
是一个字符串还是一个数字?不。据我所知,如果您坚持使用整个正则表达式解决方案,PHP不支持对同一组的捕获。谢谢Kobi。如果你有一个答案,我会接受它:-)上面的例子是一个简化,regexp实际上更复杂。我知道如何用冗长的方式去做,我只是想知道是否有一条较短的路径来解决这个问题。@downvoter:很好的downvote!这个答案怎么了?这些“提示”可能是问题下的一个评论。
Array
(
    [0] => Array
        (
            [0] => 1
            [1] => ,2
            [2] => ,3
            [3] => ,4
        )

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