黒魔術を読み解く
久々に弾さんのブログを見て、以下のソースが理解できなかったので、調べてみました。
折角なので、調べたことをメモしときます。
#!/usr/bin/perl use strict; use warnings; { no warnings 'redefine'; *CORE::GLOBAL::glob = sub{ my $expr = shift; warn $expr; $expr =~ s{ \A(.*?)~~(.*?)(\^\.)(\.\^?)(.*?) }{ my $num = eval $1; my $min = $2; my $lt0 = length($3) == 1 ? '<=' : '<'; my $lt1 = length($4) == 1 ? '<=' : '<'; my $max = $5; qq($min $lt0 $num && $num $lt1 $max); }emsx; warn $expr; eval $expr; }; } local $\="\n"; print "OK" if <length('^..^') ~~ 3^..^5>; print "OK" unless <length('^..^') ~~ 0^..^3>;http://blog.livedoor.jp/dankogai/archives/51222364.html
no warnings 'redefine';
関数を再定義する時のワーニングを抑制する。
*CORE::GLOBAL::glob = sub{
組み込みglob関数をオーバーライド(関数再定義)しています。
my $expr = shift;
glob関数の第1引数を$exprへ代入しています。
warn $expr;
標準エラー出力へ$exprの内容を出力しています。
$expr =~ s{ \A(.*?)~~(.*?)(\^\.)(\.\^?)(.*?) }{ ・・・ }emsx;
\Aは、常に文字列の先頭にのみマッチします。
ちなみに、^ では文字列中に埋め込まれた改行の直後にもマッチしてしまいます。
後の正規表現は、ちょっと問題あり・・・かも(最後の方で説明します)。
e修飾子
e修飾子は、s{}{} の右側を式とみなして実行します。
m修飾子
m修飾子は、文字列を複数行として扱います。
s修飾子
s修飾子は、ドット(.) が改行にも一致するようにします。
x修飾子
x修飾子は、パターン内のスペースを無視し、コメントを入れられるようにします。
my $num = eval $1;
今回は、length('^..^')の実行結果が$numに入ります。
my $min = $2;
今回は、3^..^5 の3が$minに入ります。
my $lt0 = length($3) == 1 ? '<=' : '<';
3項演算で、今回は3^..^5 の『^.』が$3入り、lengthは文字列『^.』なので2なり、$lt0には '<' が入ります。
my $lt1 = length($4) == 1 ? '<=' : '<';
3項演算で、今回は3^..^5 の『.^』が$4入り、lengthは文字列『.^』なので2なり、$lt1には '<' が入ります。
my $max = $5;
今回は、3^..^5 の5が入ります。
qq($min $lt0 $num && $num $lt1 $max);
文字列 "$min $lt0 $num && $num $lt1 $max" と等価です。
しかし、単なる文字列でどこにも代入していない。
たぶん、最後に評価したものが現状のもを置換して、$exprに格納されるのかな・・・たぶん。
warn $expr;
標準エラー出力へ$exprの内容を出力しています。
eval $expr;
今回は、$exprには、文字列 "$min $lt0 $num && $num $lt1 $max" が格納されていて、eval(実行)します。
local $\="\n";
print文の最後に"\n"が付加されるようです。