Rubyで%%%%%%%%%%%%%%%を実行すると空文字列("")が得られる。
ちなみに%の数は15個。
他の数のときは?
%を1つずつ増やしてevalさせてみると、最初は3つの時に空文字列を得られた。
以降は4ずつ増えたときにも得られる。
数が違うとSyntaxError。
def eval_p(n)
eval "%" * n
rescue SyntaxError
end
(1..100).select{|n| eval_p n }
# => [3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63, 67, 71, 75, 79, 83, 87, 91, 95, 99]
# 最初だけ3、以降は4ずつ増えてる
(1..100).map{|n| eval_p n }.compact
# => ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]
# ぜんぶ空文字列
理由
%%%が空文字列だった。
これはよく考えたら%||とかと同じ。(→リテラル > %記法)
じゃぁ4増えたときは?
%%%%%%%はまず最初の%%%で空文字列ができる。
その空文字列に%メソッドが呼ばれる。(→instance method String#%)
引数は空文字列%%%。
だから"" % ""と同じ。
その後もずっと"" % "" % "" % ""と連鎖してくだけ。
ためしに%メソッドにちゃんとした文字列を渡してみる。
puts %%\%s% % %%まうまう%
# => まうまう
%%hoge%の中で%を使う場合は""とかと同じく\でエスケープする。
他にも%--%%--%%--%%--%%--みたいにいくつもパターンある。
おまけ
putsのキモい代替。
$><<%%\%s\n%% "hello world"
# => hello world
今回のことを応用して無限に伸ばせる。
$><<%%\%s\n%%%%\%s%%%%\%s%%%%\%s%%%%\%s%%%%\%s%%%%\%s%%%%\%s%% "hello world"
# => hello world
ちなみに最後の%を5個にしても動く。
$><<%%\%s\n%%%%% "hello world"
# => hello world
これは今までとまた違った理由で、"a" "b"みたく文字列リテラルが連続してると連結されるため。
つまり以下と同じ。
$><<%%\%s\n%%"" "hello world"
全然関係ないけど%記法のカッコの対応について疑問
%記法は始まりと終わりの区切り文字を、単一の文字か対応するカッコで指定する。
%|abc|でabcを得られる。
%(abc)でabcを得られる。
それで
%)abc)もabcを得られる。
これはカッコは関係なくて「)」という文字を指定してると思う。
だけどその文字列の中に(を書いてしまうと、文字列を閉じることが出来なくなる。
irbでいろいろ試してみたけどダメだった。
%)abc()だと閉じられず、文字列が続く。
%)abc())だとエラー。
SyntaxError: (irb):202: syntax error, unexpected ')', expecting end-of-input from /usr/local/bin/irb:11:in `<main>'
たぶん$(()) #=> "()"みたいに、カッコの対応が取れていれば区切り文字と同じでも文字列に含められる仕様の影響と思う。
エスケープして%)abc\()って書いたらいけた。
エスケープしないで書いた場合に閉じる方法ってないのかな。
変なエラーを避けるため変な書き方は控えようと思っっ他。
参考
- リテラル