LoginSignup
4
3

More than 5 years have passed since last update.

Ruby のフォーマット文字列のマイナーな機能の紹介

Last updated at Posted at 2018-12-25

C言語に関する printf のマイナーな機能の紹介
の ruby 版。

module function Kernel.#format に書いてあることのうち、私がよく知らなかったことを中心に。

桁区切り文字を出力するフラグ文字は、無い

上記のサイトに

sprintf のすべての方言をサ ポートしていないこと(%': 3桁区切り)など

と、無いことが明言されている。残念。

%c

上記のサイトに

引数の数値(0〜255)を文字コードとみなして対応する文字を出力します。

とあるが、255 よりも大きい値も受け入れてくれる。

ruby2.5
puts( "%c" % 12354 )
#=> あ

あと。負の値の動きが怪しい。

ruby2.5
puts( ("%c" % -1).inspect )
#=> "\xFF"
puts( ("%c" % -2).inspect )
#=> "\xFE"
puts( ("%c" % -3).inspect )
#=> ArgumentError: invalid character

なんで?

%p

Object#inspect の結果を出力します。

とある。知らなかった。

ruby2.5
puts( "%p %p %p" % ["hoge", :fuga, {piyo:0}] )
#=> "hoge" :fuga {:piyo=>0}

%d

引数が整数でなければ関数 Kernel.#Integer と同じ規則で整数に 変換されます。

とある。
つまり、文字列なども適当に整数にされる。知らなかった。

ruby2.5
puts( "%d %d %d %d" % [ "\t-3\t", "077", "0xa", Time.now ] )
#=> -3 63 10 1545721423

%u

引数の数値を符号なし整数とみなして10進表現の整数として出力します。

とあるが、%d との違いがわからない。

ruby2.5
puts( "%u %u" % [ -100, "-100"] )
#=> -100 -100

なにがどう符号なし整数なのか。

%O%F は無い

%o%f はあるけど、%O%F は無い。

ruby2.5
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] )ではこんな感じ:

ruby2.5
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 を呼ぶ

上記サイトには書かれていないけど、%fFloat 以外を渡すと to_f が呼ばれる。

こんな具合。

ruby2.5
class Hoge
  def to_f
    print "Hoge#to_f : "
    return 1.0
  end
end

puts( "%f" % Hoge.new )
#=> Hoge#to_f : 1.000000

BigDecimal と併用すると、罠っぽい挙動になる。

ruby2.5
require "bigdecimal"
puts( "%.20f" % BigDecimal.new( "0.1" ) )
#=> 0.10000000000000000555

BigDecimal の 0.1 が出力されているのではなく、それを to_f した値が出力される。to_f されているので誤差がある。

16進数の浮動小数点変換指示子 %a

C言語の printf にも導入されている 16進数浮動小数点。ruby にもある。

ruby2.5
puts( "%a %A" % [0.1, 0.1] )
#=> 0x1.999999999999ap-4 0X1.999999999999AP-4

この文字列を Float に戻すには、String#scanf を使う。

ruby2.5
require 'scanf'
p "0x1.999999999999ap-4".scanf("%a")
# => [0.1]

知らなかった。
ちなみに、%a で書いたけど、 %f でもいいし、なんと %F でもいい。

%<name>

Symbol のインスタンス name をキーとする Hash を引数にした場合、 対応する値をフォーマットして参照します。

とのこと。

ruby2.5
puts("%<hoge>d %<fuga>s" % { hoge:123, fuga:"foo" } )
#=> 123 foo

という具合。便利な局面もあるかも。

%{name}

一方よく意味がわからないのが %{name}

対応する値をフォーマットせずに参照します。 幅や精度を指定するために使用することができます。

とのこと。

ruby2.5
puts("%{hoge}d %{fuga}s" % { hoge:123, fuga:"foo" } )
#=> 123d foos

なんに使うんだろうこれ。「幅や精度を指定するため」とあるけど、わからない。

4
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3