递归正则表达式是否理解命名捕获?在(?{{ code }})
的文档中有一个注释,它是一个独立的子模式,它有自己的一组捕获,当子模式完成时会被丢弃,并且(?PARNO)
中有一个注释“它类似于{{ 1}}。(?{{ code }})
在完成后会丢弃自己的命名捕获吗?
我正在写关于Perl的Mastering Perl的递归正则表达式。 perlre已经有一个平衡的parens示例(我在Matching balanced parenthesis in Perl regex中显示),所以我想我会尝试平衡引号:
(?PARNO)
这有效,两个引号显示在#!/usr/bin/perl
# quotes-nested.pl
use v5.10;
$_ =<<'HERE';
He said 'Amelia said "I am a camel"'
HERE
say "Matched!" if m/
(
['"]
(
(?:
[^'"]+
|
( (?1) )
)*
)
['"]
)
/xg;
print "
1 => $1
2 => $2
3 => $3
4 => $4
5 => $5
";
和$1
:
$3
没关系。我明白那个。但是,我不想知道这些数字。因此,我将第一个捕获组设为命名捕获,并查看Matched!
1 => 'Amelia said "I am a camel"'
2 => Amelia said "I am a camel"
3 => "I am a camel"
4 =>
5 =>
期望看到我之前在%-
和$1
中看到的两个子字符串:
$2
我只看到第一个:
use v5.10;
$_ =<<'HERE';
He said 'Amelia said "I am a camel"'
HERE
say "Matched [$+{said}]!" if m/
(?<said>
['"]
(
(?:
[^'"]+
|
(?1)
)*
)
['"]
)
/xg;
use Data::Dumper;
print Dumper( \%- );
我希望Matched ['Amelia said "I am a camel"']!
$VAR1 = {
'said' => [
'\'Amelia said "I am a camel"\''
]
};
会重复第一个捕获组中的所有内容,包括命名捕获到(?1)
。我可以通过命名一个新的捕获来解决这个问题:
said
现在我得到了我的预期:
use v5.10;
$_ =<<'HERE';
He said 'Amelia said "I am a camel"'
HERE
say "Matched [$+{said}]!" if m/
(?<said>
['"]
(
(?:
[^'"]+
|
(?<said> (?1) )
)*
)
['"]
)
/xg;
use Data::Dumper;
print Dumper( \%- );
我认为我可以通过将命名捕获移动到一个级别来解决这个问题:
Matched ['Amelia said "I am a camel"']!
$VAR1 = {
'said' => [
'\'Amelia said "I am a camel"\'',
'"I am a camel"'
]
};
但是,这并没有抓住use v5.10;
$_ =<<'HERE';
He said 'Amelia said "I am a camel"'
HERE
say "Matched [$+{said}]!" if m/
(
(?<said>
['"]
(
(?:
[^'"]+
|
(?1)
)*
)
['"]
)
)
/xg;
use Data::Dumper;
print Dumper( \%- );
中较小的子字符串:
said
我想我理解这一点,但我也知道这里有些人实际上触及了实现它的C代码。 :)
而且,当我写这篇文章时,我认为我应该重置Matched ['Amelia said "I am a camel"']!
$VAR1 = {
'said' => [
'\'Amelia said "I am a camel"\''
]
};
的STORE领带以找出答案,但后来我必须找出如何做到这一点。
答案 0 :(得分:4)
在玩完这个之后,我很满意我在问题中说的是对的。每次调用(?PARNO)
都会获得一个完整且独立的匹配变量集,并在运行结束时将其丢弃。
您可以通过使用模式匹配运算符外部的数组并在重复的子模式的末尾按下它来获取每个子模式中匹配的所有内容,如下例所示:
#!/usr/bin/perl
# nested_carat_n.pl
use v5.10;
$_ =<<'HERE';
Outside "Top Level 'Middle Level "Bottom Level" Middle' Outside"
HERE
my @matches;
say "Matched!" if m/
(?(DEFINE)
(?<QUOTE_MARK> ['"])
(?<NOT_QUOTE_MARK> [^'"])
)
(
(?<quote>(?"E_MARK))
(?:
(?&NOT_QUOTE_MARK)++
|
(?R)
)*
\g{quote}
)
(?{ push @matches, $^N })
/x;
say join "\n", @matches;
我在Chapter 2 of Mastering Perl深入探讨,你可以免费阅读(至少一段时间)。