与preg_match_all()重复匹配

问题描述 投票:10回答:6

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

$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_match_all()这样的单一功能来做到这一点?

php regex preg-match preg-match-all
6个回答
8
投票

根据Kobi(见上面的评论):

PHP不支持同一组的捕获

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


4
投票

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

$list = '1,2,3,4';
preg_match_all('|(?<=\d),\d+|', $list, $matches);
print_r($matches);

所有,\d+都在0组。

输出:

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

2
投票

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

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

但在大多数情况下,已知的令牌\G完成了这项工作。 \G 1)匹配输入字符串的开头(当没有设置\A修饰符时为^m)或2)从前一个匹配结束的地方开始匹配。说,你必须像下面这样使用它:

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

live demo here

或者如果捕获组无关紧要:

preg_match_all('/\G,?\d+/', $list, $matches);

$matches将持有这个(见live demo):

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

)

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

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

0
投票

为什么不呢:

$ar = explode(',', $list);
print_r($ar);

0
投票

当要在模式中使用要拆分的字符以匹配自身时,拆分只是一个选项。我的情况是,格式错误的逗号分隔行必须被解析为许多已知选项中的任何一个。

即选项'1,2','2','2,3'主题'1,2,3'。

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

天真的正则表达式会像'〜^(1,2 | 2 | 2,3)(?:,(1,2 | 2 | 2,3))* $ ~i',但这会遇到问题同组捕获。

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

这不是最干净的解决方案,但是当您必须处理格式错误的输入数据时,它才有效。


0
投票

来自http://www.php.net/manual/en/regexp.reference.repetition.php

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

也类似的线程:

How to get all captures of subgroup matches with preg_match_all()?

© www.soinside.com 2019 - 2024. All rights reserved.