#はじめに
以下のようなRubyのコードを見かけました。
names = ['Jon', 'Bob', 'Alice']
puts "Their names are %s, %s and %s" % names
#=> Their names are Jon, Bob and Alice
文字列中に含まれている%sやその後の%namesが何を意味しているのか分からなかったため、調べてみました。
#String#%
リファレンスを確認したところ、Stringクラスのインスタンスメソッドで%がありました。
https://docs.ruby-lang.org/ja/2.5.0/method/String/i/=25.html
self % args -> String
printf と同じ規則に従って args をフォーマットします。
args が配列であれば Kernel.#sprintf(self, *args) と同じです。 それ以外の場合は Kernel.#sprintf(self, args) と同じです。
引数argsを変換してくれるようです。
文字列 % argsというのが最初に見たコードの
"Their names are %s, %s and %s" % names
の部分と一致してそうですが、イマイチよく分かりません。
printfと同じ規則に従ってとは?
printfって何だっけ?
ということで調べてみました。
printfとは
こちらもリファレンスを確認すると、Karnelモジュールのモジュール関数に定義されていました。
https://docs.ruby-lang.org/ja/2.5.0/method/Kernel/m/printf.html
C 言語の printf と同じように、format に従い引数を文字列に変換してportに出力します。
どうやらprintfは元々C言語の関数で、ある規則に従って引数を変換し、文字列として出力してくれるようです。C言語は全く分からないのでスルーします。
つまり、String#%はprintfで使われている規則に従って引数のargsを変換してくれるメソッドのようです。
では、printfで使われている規則とは何か?
sprintf フォーマットとは
String#%のリファレンスに規則について記載されていました。
Rubyの場合はC言語のものと少し違うが、ほとんど一緒のようです。
このsprintfフォーマットの中で指示子という項目があり、その中に文字列を表す指示子としてsがありました。
指示子は引数の型の解釈を示します。指示子を省略することはできません。 指示子には大きく分けて
・文字列を表す指示子: c, s, p
・整数を表す指示子: d, i, u, b, B, o, x, X,
・浮動小数点数を表す指示子: f, g, e, E, G
があります
こちらのサイトが分かりやすかったです。
http://www9.plala.or.jp/sgwr-t/c/sec05.html
#まとめ
以上の知識を得てレベルアップしたため、最初に書いたコードを再度見てみると、以下の事が分かりました。
names = ['Jon', 'Bob', 'Alice']
"Their names are %s, %s and %s" % names
- 二行目でString#%メソッドが使用されて、 self % args の形になっている。
- 一行目で定義された配列 names が%メソッドの引数(args)になっている。
- self(文字列)の中で文字列を表す指示子sが使用されている。
したがって、%メソッドの引数に指定された配列namesの各要素が、文字列中の%s(指示子)により、文字列として表示されているようです。(間違っていたらすいません)
#おまけ
今回の例のように配列を引数にする場合、配列の要素数に対して文字列中の指示子の数が多いと、引数が不足しているというエラーになりました。
names = ['Jon', 'Bob', 'Alice']
puts "Their names are %s, %s, %s and %s" % names
# 配列の要素数は3に対して、%sを4つ使用しています。
#=> too few arguments (ArgumentError)
逆に、配列の要素数が多い場合は余剰分が無視されます。
names = ['Jon', 'Bob', 'Alice']
puts "Their names are %s and %s" % names
# 配列の要素数は3に対して、%sを2つ使用しています。
#=> Their names are Jon and Bob
#余計な存在の'Alice'は無視されます。