私は現在、正規表現について学習しており、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
の代わりに使用すると、 utf8がオンのA-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]