読み難いワンライナー

はてブを眺めていたら以下のような質問を見付けたので、解説してみるよ!

perl の構文に関する質問です。
このコードが何をやっているのか教えてください。

$_=3x(1E3-1),s/3/++$p%3*$p%5?7:5x$p/ge,print s/5//g

以下のコードと同じで3または5で割り切れる1000までの数を足した結果が得られることは知っていまが、それぞれの記号が何を意味するのか分かりません。

$sum=0;
map {$sum += $_ if(!($_%3) || !($_%5))} 1..1000;
print $sum;

最近 perl を使い始めたので良くわかっていません。
よろしくお願いします。

http://q.hatena.ne.jp/1246252336

予備知識

まずは、これを解読するために必要な知識は以下

という訳で、一つずつ簡単な解説いってみよう。

  • 暗黙の $_

これは特殊変数とか言われてる奴かな。
正規表現や一部の組み込み関数などでは、対象や引数が渡されなかった時に $_ っていう変数を勝手に使います。

$_ = 111;
print $_; # => 111
print;    # => 111

繰り返し演算子です。文字列に使うと、指定回数繰り返した文字列になりますね。

my $str = "Abc";
print $str x 3; # => "AbcAbcAbc"
  • 指数表記

これはもう表現の問題でして、1E3 は 1 * (10 ** 3) 、つまり 1000 という事ですね。

s/// は、対象となる変数を置換し、置換処理をした回数を返します。

$_ = "113";
print s/1/2/; # => 1
print; # => 213

$_ = "113";
# g修飾子を使うと
print s/1/2/g; # => 2
print; # => 223

g修飾子は繰り返しの指定になります。
この例ですと、付けない場合は一度置換した時点で終了していますけど、付けたほうは最後まで頑張ります!

$_ = "113"s/1/2x2/e; # e修飾子を使うと...
print; # => 2213

e修飾子は正規表現中の Perl コードを評価してくれるようになります。
この場合は x演算子 で 2 を 2回繰り返し、それを置換する結果として利用してます。

$_ = "113";
s/1/2x2/ge; # 合せ技!
print; # => 22223

組み合わせるとこんな風になりますね。

解説

という訳で対象となるコードをもう一度見てみましょう。

$_=3x(1E3-1),s/3/++$p%3*$p%5?7:5x$p/ge,print s/5//g

はい、ここまでの予備知識でなんとかなりそうですね。


僕はもう疲れましたのでここまでにしておきます。
続きが読みたい方はわっふるわ(ry