这是官方常见问题解答 http://faq.perl.org/perlfaq6.html#Can_I_use_Perl_regul减去任何后续编辑。
您的第一次尝试可能应该是文本::平衡 http://search.cpan.org/perldoc/Text::Balanced模块,自 Perl 5.8 起就包含在 Perl 标准库中。它具有多种处理棘手文本的功能。这正则表达式::常见 http://search.cpan.org/perldoc/Regexp::Common模块还可以通过提供您可以使用的固定模式来提供帮助。
从 Perl 5.10 开始,您可以使用递归模式将平衡文本与正则表达式进行匹配。在 Perl 5.10 之前,您必须诉诸各种技巧,例如在(??{})
序列。
这是使用递归正则表达式的示例。目标是捕获尖括号内的所有文本,包括嵌套尖括号内的文本。此示例文本有两个“主要”组:一个具有一层嵌套的组和一个具有两层嵌套的组。尖括号中共有五组:
I have some <brackets in <nested brackets> > and
<another group <nested once <nested twice> > >
and that's it.
匹配平衡文本的正则表达式使用两个新的(对于 Perl 5.10)正则表达式功能。这些内容涵盖在perlre http://perldoc.perl.org/perlre.html此示例是该文档中示例的修改版本。
首先,添加新的所有格+
到任何量词都会找到最长的匹配并且不会回溯。这很重要,因为您想通过递归处理任何尖括号,而不是回溯。群组[^<>]++
查找一个或多个非尖括号而不回溯。
二、新(?PARNO)
指的是特定捕获组中的子模式PARNO
。在下面的正则表达式中,第一个捕获组找到(并记住)平衡文本,并且您需要在第一个缓冲区中使用相同的模式来越过嵌套文本。这就是递归部分。这(?1)
使用外部捕获组中的模式作为正则表达式的独立部分。
把它们放在一起,你有:
#!/usr/local/bin/perl5.10.0
my $string =<<"HERE";
I have some <brackets in <nested brackets> > and
<another group <nested once <nested twice> > >
and that's it.
HERE
my @groups = $string =~ m/
( # start of capture group 1
< # match an opening angle bracket
(?:
[^<>]++ # one or more non angle brackets, non backtracking
|
(?1) # found < or >, so recurse to capture group 1
)*
> # match a closing angle bracket
) # end of capture group 1
/xg;
$" = "\n\t";
print "Found:\n\t@groups\n";
输出显示 Perl 找到了两个主要组:
Found:
<brackets in <nested brackets> >
<another group <nested once <nested twice> > >
通过一些额外的工作,您可以将所有组放在尖括号中,即使它们也位于其他尖括号中。每次获得平衡匹配时,请删除其外部分隔符(这是您刚刚匹配的分隔符,因此不要再次匹配它)并将其添加到要处理的字符串队列中。继续这样做,直到没有匹配项为止:
#!/usr/local/bin/perl5.10.0
my @queue =<<"HERE";
I have some <brackets in <nested brackets> > and
<another group <nested once <nested twice> > >
and that's it.
HERE
my $regex = qr/
( # start of bracket 1
< # match an opening angle bracket
(?:
[^<>]++ # one or more non angle brackets, non backtracking
|
(?1) # recurse to bracket 1
)*
> # match a closing angle bracket
) # end of bracket 1
/x;
$" = "\n\t";
while( @queue )
{
my $string = shift @queue;
my @groups = $string =~ m/$regex/g;
print "Found:\n\t@groups\n\n" if @groups;
unshift @queue, map { s/^<//; s/>$//; $_ } @groups;
}
输出显示所有组。最外面的匹配项首先显示,嵌套的匹配项稍后显示:
Found:
<brackets in <nested brackets> >
<another group <nested once <nested twice> > >
Found:
<nested brackets>
Found:
<nested once <nested twice> >
Found:
<nested twice>