【发布时间】:2012-03-30 06:26:13
【问题描述】:
我正在用 perl 编写一个正则表达式来匹配启动 perl 子例程定义的 perl 代码。这是我的正则表达式:
my $regex = '\s*sub\s+([a-zA-Z_]\w*)(\s*#.*\n)*\s*\{';
$regex 匹配启动子例程的代码。我还试图在 $1 中捕获子例程的名称,以及在子例程名称和 $2 中的初始左大括号之间的任何空格和 cmets。 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”,而不是我想要的三行 cmets。我以为正则表达式会贪婪地将所有三行 cmets 放入 $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.
'
【问题讨论】:
-
另见
PPI。例如,$subs=PPI::Document->new(\$code_string)->find('PPI::Statement::Sub');...
标签: regex perl regex-greedy