任务很清楚。在输入中我们有一个变量正则表达式模式,据说它包含命名的子模式,在输出中我们需要获得一个子模式名称数组:
function get_subpattern_names($any_input_pattern) {
// What pattern to use here?
$pattern_to_get_names = '/.../';
preg_match_all($pattern_to_get_names, $any_input_pattern, $matches);
return $matches;
}
所以问题是在上面的函数中使用$pattern_to_get_names
的内容是什么?
例如:
get_subpattern_names('/(?P<name>\w+): (?P<digit>\d+)/');
应该返回:
array('name', 'digit');
P.S。:根据PCRE documentation子模式名称,最多包含32个字母数字字符和下划线。
由于我们无法控制输入模式,因此我们需要考虑所有可能的命名语法。根据{{3}}他们是:
(?P<name>pattern)
,(?<name>pattern)
和(?'name'pattern)
。
我们还需要考虑嵌套的子模式,例如:
(?<name1>.*(?<name2>pattern).*)
。
无需计算重复名称,保留外观顺序,或获取数字,非捕获或其他类型的子模式。如果存在,只需列出名称。
答案 0 :(得分:3)
您可以使用
获取所有有效命名捕获组名称的列表"~(?<!\\\\)(?:\\\\{2})*\(\?(?|P?<([_A-Za-z]\w{0,31})>|'([_A-Za-z]\w{0,31})')~"
请参阅regex和online PHP demo。
重点是匹配未跟随(
的{{1}}跟随?
,然后跟P<
或<
,然后组名模式结束>
或'
后面跟着群组名称模式,然后是'
。
$rx = "~(?<!\\\\)(?:\\\\{2})*\(\?(?|P?<([_A-Za-z]\w{0,31})>|'([_A-Za-z]\w{0,31})')~";
$s = "(?P<name>\w+): (?<name2>\w+): (?'digit'\d+)";
preg_match_all($rx, $s, $res);
print_r($res[1]);
产量
Array
(
[0] => name
[1] => name2
[2] => digit
)
模式详情
(?<!\\)
- 紧靠当前位置左侧的\
(?:\\\\)*
- 0+双反斜杠(允许(
之前的任何转义反斜杠)\(
- (
\?
- ?
(?|P?<([_A-Za-z]\w{0,31})>|'([_A-Za-z]\w{0,31})')
- 分支重置组:
P?<([_A-Za-z]\w{0,31})>
- 可选的P
,<
,_
或ASCII字母,0到31个字符(数字/字母/ _
) (捕获到第1组)和>
|
- 或'([_A-Za-z]\w{0,31})'
- '
,_
或ASCII字母,0到31个字符(数字/字母/ _
)(也被捕获到第1组),然后'
组名模式都被捕获到组1中,您只需要获得$res[1]
。
答案 1 :(得分:1)
Wiktor的解决方案似乎非常彻底,但这就是我想出来的。
print_r(get_subpattern_names('/(?P<name>\w+): (?P<digit>\d+)/'));
function get_subpattern_names($input_pattern){
preg_match_all('/\?P\<(.+?)\>/i', $input_pattern, $matches);
return $matches[1];
}
这适用于大多数情况。更重要的是,这更具可读性和不言自明。
基本上,我搜索?P<
后跟(.+?)
,后者转换为角括号之间的某个non-greedy版本。然后该函数返回$matches
数组中的第一个偏移量,该偏移量指向匹配的第一组括号。