我正在用 perl 编写一个正则表达式来匹配开始 perl 子例程定义的 perl 代码。这是我的正则表达式:
my $regex = '\s*sub\s+([a-zA-Z_]\w*)(\s*#.*\n)*\s*\{';
$regex 匹配启动子程序的代码。我还试图在 $1 中捕获子例程的名称以及子例程名称和 $2 中的初始大括号之间的任何空格和注释。 2 美元给我带来了问题。
考虑以下 perl 代码:
my $x = 1;
sub zz
# This is comment 1.
# This is comment 2.
# This is comment 3.
{
$x = 2;
return;
}
当我将此 perl 代码放入一个字符串并将其与 $regex 进行匹配时,$2 是“#This is comment 3.\n”,而不是我想要的三行注释。我以为正则表达式会贪婪地将所有三行注释都放入 $2 中,但事实并非如此。
我想了解为什么 $regex 不起作用并设计一个简单的替代品。正如下面的程序所示,我有一个更复杂的替代品 ($re3) 有效。但我认为了解 $regex 为何不起作用对我来说很重要。
use strict;
use English;
my $code_string = <<END_CODE;
my \$x = 1;
sub zz
# This is comment 1.
# This is comment 2.
# This is comment 3.
{
\$x = 2;
return;
}
END_CODE
my $re1 = '\s*sub\s+([a-zA-Z_]\w*)(\s*#.*\n)*\s*\{';
my $re2 = '\s*sub\s+([a-zA-Z_]\w*)(\s*#.*\n){0,}\s*\{';
my $re3 = '\s*sub\s+([a-zA-Z_]\w*)((\s*#.*\n)+)?\s*\{';
print "\$code_string is '$code_string'\n";
if ($code_string =~ /$re1/) {print "For '$re1', \$2 is '$2'\n";}
if ($code_string =~ /$re2/) {print "For '$re2', \$2 is '$2'\n";}
if ($code_string =~ /$re3/) {print "For '$re3', \$2 is '$2'\n";}
exit 0;
__END__
上面的 perl 脚本的输出如下:
$code_string is 'my $x = 1;
sub zz
# This is comment 1.
# This is comment 2.
# This is comment 3.
{
$x = 2;
return;
} # sub zz
'
For '\s*sub\s+([a-zA-Z_]\w*)(\s*#.*\n)*\s*\{', $2 is '# This is comment 3.
'
For '\s*sub\s+([a-zA-Z_]\w*)(\s*#.*\n){0,}\s*\{', $2 is '# This is comment 3.
'
For '\s*sub\s+([a-zA-Z_]\w*)((\s*#.*\n)+)?\s*\{', $2 is '
# This is comment 1.
# This is comment 2.
# This is comment 3.
'
最佳答案
仅查看捕获 $2
的正则表达式部分.是(\s*#.*\n)
.就其本身而言,这只能捕获单个注释行。在它后面有一个星号以捕获多个注释行,这很好用。它捕获多个注释行并将它们每个放入 $2
,一一,每次替换之前的值$2
.所以$2
的最终值当正则表达式完成时,匹配是捕获组匹配的最后一件事,也就是最后的注释行。仅有的。要修复它,您需要将星号放在捕获组中。但是随后您需要放置另一组括号(这次是非捕获)以确保星号适用于整个事情。所以,而不是 (\s*#.*\n)*
, 您需要 ((?:\s*#.*\n)*)
.
您的第三个正则表达式有效,因为您不知不觉地将整个表达式括在括号中,以便您可以在其后加上问号。这引起了$2
一次捕获所有评论,以及 $3
仅捕获最终评论。
当您调试正则表达式时,请确保打印出您正在使用的所有匹配变量的值:$1
, $2
, $3
等。你会看到 $1
只是子程序的名称和 $2
只是第三条评论。这可能让您想知道,当第一个和第二个捕获组之间没有任何内容时,您的正则表达式究竟是如何跳过前两个注释的,这最终会引导您发现捕获组多次匹配时会发生什么。
顺便说一句,您似乎还在将子程序名称后面的任何空格捕获到 $1
中。 .这是故意的吗? (糟糕,我弄乱了我的助记符并认为 \w
是“w 表示空格”。)
关于regex - Perl 正则表达式不够贪婪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9691052/