我目前正在学习正则表达式,并且正在尝试创建一个正则表达式来匹配 Perl 中的任何合法变量名。
这是我到目前为止写的:
^\$[A-Za-z_][a-zA-Z0-9_]*
唯一的问题是正则表达式对特殊符号返回 true,例如字符串$a&将返回 true。
我做错了什么?
谢谢!罗腾
解析 Perl 很困难,关于什么是变量和什么不是变量的规则也很复杂。如果您尝试解析 Perl,请考虑改用PPI。它可以解析 Perl 程序并执行诸如查找所有变量之类的操作。PPI 是perlcritic用来完成工作的。
如果你想尝试去做,这里有一些边缘情况需要考虑......
$^F
$/
${^ENCODING}
$1
$élite # with utf8 on
${foo}
*{foo} = \42;
*{$name} = \42; # with strict off
${$name} = 42; # with strict off
当然还有其他的印记@%*
。并检测是否在单引号字符串中。这是我强烈鼓励您使用 PPI 而不是自己尝试的方式。
如果您想练习,实际的练习是将变量从更大的字符串中提取出来,而不是进行精确匹配。
# Match the various sigils.
my $sigils = qr{ [\$\@\%*] }x;
# Match $1 and @1 and so on
my $digit_var = qr{ $sigils \d+ }x;
# Match normal variables
my $named_var = qr{ $sigils [\w^0-9] \w* }x;
# Combine all the various variable matches
my $match_variable = qr{ ( $named_var | $digit_var ) }x;
这使用()
捕获操作符来抓取变量。它还使用/x
修饰符使正则表达式更易于阅读,并使用替代分隔符来避免倾斜牙签综合症。使用\w
而不是确保在utf8A-Z
开启时会拾取 Unicode 字符,而在关闭时不会。最后,用于分段构建正则表达式。填补空白留作练习。qr
最后你需要 a $
,否则它只是尽可能匹配并忽略其余部分。所以应该是:
^\$[A-Za-z_][A-Za-z0-9]*$
我需要解决这个问题来创建一个简单的源代码分析器。
此子例程从代码的输入部分提取 Perl 用户变量
sub extractVars {
my $line = shift;
chomp $line;
$line =~ s/#.*//; # Remove comments
$line =~ s/\s*;\s*$//; # Remove trailing ;
my @vars = ();
my $match = 'junk';
while ($match ne '') {
push @vars, $match if $match ne 'junk';
$match = '';
if ($line =~ s/(
[\@\$\%] # $@%
{? # optional brace
\$? # optional $
[\w^0-9] # begin var name
[\w\-\>\${}\[\]'"]* # var name
[\w}\]] # end var name
|
[\@\$\%] # $@%
{? # optional brace
\$? # optional $
[\w^0-9] # one letter var name
[}\]]? # optional brace or bracket
)//x) {
$match = $1;
next;
}
}
return @vars;
}
使用以下代码对其进行测试:
my @variables = extractVars('$a $a{b} $a[c] $scalar @list %hash $list[0][1] $list[-1] $hash{foo}{bar} $aref->{foo} $href->{foo}->{bar} @$aref %$hash_ref %{$aref->{foo}} $hash{\'foo\'} "$a" "$var{abc}"');
如果变量名包含空格,则它不起作用,例如:
$hash{"baz qux"}
${ $var->{foo} }[0]