我有以下正则表达式来捕获数字列表(最终会比这更复杂):
$list = '10,9,8,7,6,5,4,3,2,1';
$regex =
<<<REGEX
/(?x)
(?(DEFINE)
(?<number> (\d+) )
(?<list> (?&number)(,(?&number))* )
)
^(?&list)/
REGEX;
$matches = array();
if (preg_match($regex,$list,$matches)==1) {
print_r($matches);
}
哪些输出:
Array ( [0] => 10,9,8,7,6,5,4,3,2,1 )
如何捕获 $matches 数组中列表中的各个数字?尽管在数字周围放置了一个捕获组 (\d+),但我似乎无法做到这一点。
编辑
为了更清楚地说明,我想最终使用递归,所以 explode 并不理想:
$match =
<<<REGEX
/(?x)
(?(DEFINE)
(?<number> (\d+) )
(?<member> (?&number)|(?&list) )
(?<list> \( ((?&number)|(?&member))(,(?&member))* \) )
)
^(?&list)/
REGEX;
最佳答案
(?(DEFINE)...)
的目的部分仅用于定义命名子模式,您可以稍后在定义部分本身或主模式中使用。由于这些子模式未在主模式中定义,因此它们不会捕获任何内容,并且引用 (?&number)
只是子模式 \d+
的一种别名并且也没有捕获任何东西。
字符串示例:1abcde2
如果我使用此模式:/^(?<num>\d).....(?&num)$/
仅1
在num组中捕获,(?&num)
不捕获任何内容,它只是 \d
的别名.
/^(?<num>\d).....\d$/
产生完全相同的结果。
还有一点需要澄清。使用 PCRE(PHP 正则表达式引擎),捕获组(命名或未命名)只能存储一个值,即使您重复它也是如此。
您的方法的主要问题是您试图同时做两件事:
- 您想要检查字符串的格式。
- 您想要提取未知数量的项目。
这样做仅在特定情况下才有可能,但一般情况下是不可能的。
例如,使用如下平面列表:$list = '10,9,8,7,6,5,4,3,2,1';
如果没有嵌套元素,您可以使用类似 preg_match_all
的函数以这种方式多次重复使用相同的模式:
if (preg_match_all('~\G(\d+)(,|$)~', $list, $matches) && !end($matches[2])) {
// \G ensures that results are contiguous
// you have all the items in $matches[1]
// if the last item of $matches[2] is empty, this means
// that the end of the string is reached and the string
// format is correct
echo '<°)))))))>';
}
现在,如果您有一个像 $list = '10,9,(8,(7,6),5),4,(3,2),1';
这样的嵌套列表例如,您想要检查格式并生成如下树结构:
[ 10, 9, [ 8, [ 7, 6 ], 5 ], 4 , [ 3, 2 ], 1 ]
单次通过是无法做到这一点的。您需要一种模式来检查整个字符串格式,并需要另一种模式来提取元素(以及一个递归函数来使用它)。
<<<FORGET_THIS_IMMEDIATELY
顺便说一句,你可以用 eval
来做到这一点和strtr
,但这是一种非常肮脏和危险的方式:
eval('$result=[' . strtr($list, '()', '[]') . '];');
FORGET_THIS_IMMEDIATELY;
关于php - PHP 中的正则表达式命名捕获组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31677485/