我试图让所有子串与乘数匹配:
$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()
这样的单一功能来做到这一点?
使用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
)
)
确实,PHP(或更好的说PCRE)不存储重复捕获组的值以供以后访问(请参阅PCRE docs):
如果捕获子模式重复匹配,则它是返回的匹配字符串的最后一部分。
但在大多数情况下,已知的令牌\G
完成了这项工作。 \G
1)匹配输入字符串的开头(当没有设置\A
修饰符时为^
或m
)或2)从前一个匹配结束的地方开始匹配。说,你必须像下面这样使用它:
preg_match_all('/^\d+|\G(?!^)(,?\d+)\K/', $list, $matches);
或者如果捕获组无关紧要:
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);
为什么不呢:
$ar = explode(',', $list);
print_r($ar);
当要在模式中使用要拆分的字符以匹配自身时,拆分只是一个选项。我的情况是,格式错误的逗号分隔行必须被解析为许多已知选项中的任何一个。
即选项'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))?'这会导致“未使用”匹配的空字符串结果。
这不是最干净的解决方案,但是当您必须处理格式错误的输入数据时,它才有效。
来自http://www.php.net/manual/en/regexp.reference.repetition.php:
当重复捕获子模式时,捕获的值是与最终迭代匹配的子字符串。
也类似的线程:
How to get all captures of subgroup matches with preg_match_all()?