web-dev-qa-db-ja.com

Perl m //でのPerl変数の展開

Perlはm//一致演算子で変数をどのように展開しますか?私が読んだのは、m//は変数の拡張/補間を1回だけ行うということです。しかし、Unmatched ( in regexが展開されているときに$patを取得するのはなぜですか?

my $pat = '(\\)';
'\\' =~ /(\\)/  ? print "OK\n" : print "NO MATCH!\n";   # OK
'\\' =~ /$pat/  ? print "OK\n" : print "NO MATCH!\n";   # Unmatched ( in regex

my $pat2 = '(\\\)';
'\\' =~ /$pat2/  ? print "OK\n" : print "NO MATCH!\n";  # OK
2
Axel Bregnsbo

あなたの問題は、バックスラッシュの周りの難解なルールを誤って適用したり、覚えていなかったことです。

一重引用符で囲まれた文字列リテラル では、

バックスラッシュは、デリミタまたは別のバックスラッシュが後に続かない限りバックスラッシュを表します。その場合、デリミタまたはバックスラッシュは補間されます。

したがって、_$pat_の値は3文字の文字列_(\)_です。これは、ソースコードのバックスラッシュの後に別のバックスラッシュが続き、これが単一のバックスラッシュを表すためです。 _$pat2_の値は、4文字の文字列_(\\)_です。これは、ソースコードの最初の2つのバックスラッシュが1つのバックスラッシュを表し、3番目のバックスラッシュの後に_)_が続くため、そのままになります。文字列の2番目のバックスラッシュになる。

正規表現 では、英数字でない限り、バックスラッシュは次の文字を引用します。 _/$pat/_は/(\)/に相当します。これはオープングループの後にリテラルの閉じ括弧が続き、グループを閉じる_)_がありません。 _/$pat2/_は、オープングループ、バックスラッシュ、クローズグループである/(\\)/と同等です。

$patに割り当てると、最初の円記号が2番目の円記号をエスケープするため、結果の文字列には円記号が1つだけ含まれます。正規表現が処理されると、閉じ括弧がエスケープされ、キャプチャグループを閉じるためのエスケープされていない括弧は残りません。

つまり、m//はバックスラッシュを1回だけ解釈しますが、'...'内でも解釈されるため、合計で2回処理されます。

$ cat p.pl 
$pat = '(\\)'; print $pat
$ Perl -l p.pl 
(\)

manual から:

引用のような演算子
q/STRING/
'STRING'
単一引用符で囲まれたリテラル文字列。バックスラッシュは、デリミタまたは別のバックスラッシュが後に続かない限りバックスラッシュを表します。その場合、デリミタまたはバックスラッシュは補間されます。

(もちろん、これはシェルでのバックスラッシュと単一引用符の動作とは異なります。)

3
ilkkachu