C言語に関する printf のマイナーな機能の紹介
の ruby 版。
module function Kernel.#format に書いてあることのうち、私がよく知らなかったことを中心に。
桁区切り文字を出力するフラグ文字は、無い
上記のサイトに
sprintf のすべての方言をサ ポートしていないこと(%': 3桁区切り)など
と、無いことが明言されている。残念。
%c
上記のサイトに
引数の数値(0〜255)を文字コードとみなして対応する文字を出力します。
とあるが、255 よりも大きい値も受け入れてくれる。
puts( "%c" % 12354 )
# => あ
あと。負の値の動きが怪しい。
puts( ("%c" % -1).inspect )
# => "\xFF"
puts( ("%c" % -2).inspect )
# => "\xFE"
puts( ("%c" % -3).inspect )
# => ArgumentError: invalid character
なんで?
%p
Object#inspect の結果を出力します。
とある。知らなかった。
puts( "%p %p %p" % ["hoge", :fuga, {piyo:0}] )
# => "hoge" :fuga {:piyo=>0}
%d
引数が整数でなければ関数 Kernel.#Integer と同じ規則で整数に 変換されます。
とある。
つまり、文字列なども適当に整数にされる。知らなかった。
puts( "%d %d %d %d" % [ "\t-3\t", "077", "0xa", Time.now ] )
# => -3 63 10 1545721423
%u
引数の数値を符号なし整数とみなして10進表現の整数として出力します。
とあるが、%d
との違いがわからない。
puts( "%u %u" % [ -100, "-100"] )
# => -100 -100
なにがどう符号なし整数なのか。
%O
や %F
は無い
%o
と %f
はあるけど、%O
と %F
は無い。
puts( "%o" % 63 )
# => 77
puts( "%O" % 63 )
# => ArgumentError: malformed format string - %O
puts( "%f" % 63.0 )
# => 63.000000
puts( "%F" % 63.0 )
# => ArgumentError: malformed format string - %F
両方受け入れそうなもんだけど、大文字はエラー。
ruby の書式文字列で指示子に使える文字を列挙すると、
aAbBcdeEfgGiopsuxX
となる。意外と大文字は使えない。
%f
, %e
, %E
, %g
, %G
はシステム依存
f, e, E, g, G に関しては sprintf(3) の結果を利用しています。従って出力結果は 実際にはシステムに依存することになります。
とあるので、OSやらに依存するらしい。手元( macOS, ruby 2.5.3p105 (略) [x86_64-darwin18] )ではこんな感じ:
puts("%f %g %G %e %E %a %A" % ([Float::INFINITY]*7))
# => Inf Inf Inf Inf Inf Inf Inf
puts("%f %g %G %e %E %a %A" % ([Float::NAN]*7))
# => NaN NaN NaN NaN NaN NaN NaN
前述のサイトとは出力が異なるね。
ところで。
OS付属の sprintf
はロケールによって、小数点がコンマになったりするけど、そのあたりはどうなってるんだろう。
ロケールを変える方法がわからなかった。
%f
, %g
, %G
, %e
, %E
, %a
, %A
は、to_f
を呼ぶ
上記サイトには書かれていないけど、%f
に Float
以外を渡すと to_f
が呼ばれる。
こんな具合。
class Hoge
def to_f
print "Hoge#to_f : "
return 1.0
end
end
puts( "%f" % Hoge.new )
# => Hoge#to_f : 1.000000
BigDecimal
と併用すると、罠っぽい挙動になる。
require "bigdecimal"
puts( "%.20f" % BigDecimal.new( "0.1" ) )
# => 0.10000000000000000555
BigDecimal
の 0.1 が出力されているのではなく、それを to_f
した値が出力される。to_f
されているので誤差がある。
16進数の浮動小数点変換指示子 %a
C言語の printf
にも導入されている 16進数浮動小数点。ruby にもある。
puts( "%a %A" % [0.1, 0.1] )
# => 0x1.999999999999ap-4 0X1.999999999999AP-4
この文字列を Float
に戻すには、String#scanf
を使う。
require 'scanf'
p "0x1.999999999999ap-4".scanf("%a")
# => [0.1]
知らなかった。
ちなみに、%a
で書いたけど、 %f
でもいいし、なんと %F
でもいい。
%<name>
Symbol のインスタンス name をキーとする Hash を引数にした場合、 対応する値をフォーマットして参照します。
とのこと。
puts("%<hoge>d %<fuga>s" % { hoge:123, fuga:"foo" } )
# => 123 foo
という具合。便利な局面もあるかも。
%{name}
一方よく意味がわからないのが %{name}
。
対応する値をフォーマットせずに参照します。 幅や精度を指定するために使用することができます。
とのこと。
puts("%{hoge}d %{fuga}s" % { hoge:123, fuga:"foo" } )
# => 123d foos
なんに使うんだろうこれ。「幅や精度を指定するため」とあるけど、わからない。