【format】引数でよく見かける'%010d'の実態を解明[Ruby]

#**はじめに**
Ruby on Railsで開発している中で、数値が動的に変化するために桁数が不統一になり、実装に悩むことがございました。そんな時、`format`メソッドに出会い、formatメソッドが開発を大いに助けてくれました。ですので、その時に得た知識を備忘録として記録しておきます。

#**format(= sprintf)メソッドとは**
formatメソッドは、**フォーマットに従って文字列を生成（整形）し、オブジェクトとして返します**。
formatメソッドを使えば、例えば数字を返す時に10進数だけでなく、8進数や16進数で表示させたり、小数点の場合、何桁まで表示させるか、といった指定を簡単に行うことができます。
`sprintf`メソッドもよく見かけますが、こちらはformatメソッドの別名です（逆も然り）。
**`sprintf`は`string print formatted`の略称**であることを知っていると理解の助けになるかと思います。

#**printfメソッドとは**
`printf`メソッドの実態はformat(sprintf)メソッドと基本的には変わりありません。
違いは、`format(sprintf)`メソッドが整形した文字列をオブジェクトとして返すのに対し、`printf`メソッドは**コンソールに出力する**点です。
また、**`printf`は`print formatted`の略称**です。

#**時間がない方は**
記事の最後に'%010d'の実態を明かしていますので飛ばしてお読みいただいて構いません。

#**指示子**
フォーマットの基本は`%指示子`の形式です。指示子によって与えられたデータをどのように整形するかが決められます。

##**%d(or %i)**
**整数を10進数で表現できます。**

最初の引数は文字列で、その中で`%文字`という形式でどのように整形するかを指定し、それ以降の引数でフォーマット中の`%文字`に対応する値を順番に指定します。
また、`文字列 % 配列`の形式でも指定することができます。


例で確認した方がわかりやすいので、いくつか載せておきます。

```
$ irb
irb(main):001:0> format('第二引数は%dです', 7)
=> "第二引数は7です"
irb(main):002:0> format('%d/%d/%d' % [2018, 12, 21])
=> "2018/12/21"
```
ここで、フォーマットのフラグというものについて軽く記述します。
**フラグは`「%」と指示子`の間に指定することができるものです。**

フラグには、`#`、`-`、`+`、`空白`、`0`の5種類があります。
1. `#` : %b,%B(2進数表現)、%o(8進数表現)、%x,%X(16進数表現)についてリテラル表現と同じプレフィックス(`0b`,`0B`,`0`,`0x`,`0X`)を出力
2. `-` : 幅を指定した場合に出力を左寄せする
3. `+` : 「+」か「-」の符号を出力する
4. `空白` : 負の数の時のみ符号「-」を出力する
5. `0` : 最小幅を指定する際に余った桁を空白ではなく「0」で埋める

```
irb(main):003:0> format('%d', 7)
=> "7"
irb(main):004:0> format('%#d', 7)
=> "7"
irb(main):005:0> format('%-d', 7)
=> "7"
irb(main):006:0> format('%+d', 7)
=> "+7"
irb(main):007:0> format('% d', 7)
=> " 7"
irb(main):008:0> format('%0d', 7)
=> "7"
```
フラグの効果の違いがわかりづらいですね。
次の例もみて確認しましょう。５の最小幅（出力の最小の桁数）を指定して、フラグの挙動の違いを再度みていきます（５という数字に意味はありません）。

```
irb(main):009:0> format('%5d', 7)
=> "    7"
irb(main):010:0> format('%#5d', 7)
=> "    7"
irb(main):011:0> format('%-5d', 7)
=> "7    "
irb(main):012:0> format('%+5d', 7)
=> "   +7"
irb(main):013:0> format('% 5d', 7)
=> "    7"
irb(main):014:0> format('%05d', 7)
=> "00007"
```
上の`#`の挙動は依然わかりづらいですね。というのも10進数（`%d`）表現しているため、今回は`#`を指定していないと同然だからです。

##**%b(or %B)**
**整数を2進数で表現できます。**

```
irb(main):001:0> format('%b', 7)
=> "111"
irb(main):002:0> format('%#b', 7)
=> "0b111"
irb(main):003:0> format('%-b', 7)
=> "111"
irb(main):004:0> format('%+b', 7)
=> "+111"
irb(main):005:0> format('% b', 7)
=> " 111"
irb(main):006:0> format('%0b', 7)
=> "111"
```
次は、先程と同様、5の最小幅を指定してみていきましょう。

```
irb(main):007:0> format('%5b', 7)
=> "  111"
irb(main):008:0> format('%#5b', 7)
=> "0b111"
irb(main):009:0> format('%-5b', 7)
=> "111  "
irb(main):010:0> format('%+5b', 7)
=> " +111"
irb(main):011:0> format('% 5b', 7)
=> "  111"
irb(main):012:0> format('%05b', 7)
=> "00111"
```
これで`#`の挙動が確認できました。リテラル表現と同じプレフィックス`「0b」`が出力されています。

##**%o**
**整数を8進数で表現できます。**

```
$ irb
irb(main):001:0> format('%5o', 9)
=> "   11"
irb(main):002:0> format('%#5o', 9)
=> "  011"
irb(main):003:0> format('%-5o', 9)
=> "11   "
irb(main):004:0> format('%+5o', 9)
=> "  +11"
irb(main):005:0> format('% 5o', 9)
=> "   11"
irb(main):006:0> format('%05o', 9)
=> "00011"
```

##**%x(or %X)**
**整数を16進数で表現できます。**

```
$ irb
irb(main):001:0> format('%5x', 15)
=> "    f"
irb(main):002:0> format('%#5x', 15)
=> "  0xf"
irb(main):003:0> format('%-5x', 15)
=> "f    "
irb(main):004:0> format('%+5x', 15)
=> "   +f"
irb(main):005:0> format('% 5x', 15)
=> "    f"
irb(main):006:0> format('%05x', 15)
=> "0000f"
```
一応、16についても確認します。

```
irb(main):007:0> format('%5X', 16)
=> "   10"
irb(main):008:0> format('%#5X', 16)
=> " 0X10"
irb(main):009:0> format('%-5X', 16)
=> "10   "
irb(main):010:0> format('%+5X', 16)
=> "  +10"
irb(main):011:0> format('% 5X', 16)
=> "   10"
irb(main):012:0> format('%05X', 16)
=> "00010"
```

##**%s**
文字列を生成します。`引数.to_s`を呼びます。

```
$ irb
irb(main):001:0> format('Hello, %s!', 'takuyanin')
=> "Hello, takuyanin!"
irb(main):002:0> "Hello, takuyanin version#{format('%d', 2)}"
=> "Hello, takuyanin version2"
```
上記のように、formatメソッドは式展開でも使うことができます。

ここで、**精度**について取り上げます。
`%s`と`%p`に対して精度`.`を適用すると、**最大桁数を指定することができます。**

```
irb(main):003:0> format('%s', 'takuyanin')
=> "takuyanin"
irb(main):004:0> format('%.s', 'takuyanin')
=> ""
irb(main):005:0> format('%.1s', 'takuyanin')
=> "t"
irb(main):006:0> format('%.5s', 'takuyanin')
=> "takuy"
irb(main):007:0> format('%.10s', 'takuyanin')
=> "takuyanin"
irb(main):008:0> format('%10s', 'takuyanin')
=> " takuyanin"
```

##**%p**
pメソッドと同じ形式で出力します。`引数.inspect`を呼びます。

```
$ irb
irb(main):001:0> format('%p', 'takuyanin')
=> "\"takuyanin\""
```

##**%f**
**浮動小数点数を出力します。**

指示子が`%f`の時は、**精度は小数点以下の桁数を示します**。

```
$ irb
irb(main):001:0> format('%f', Math::PI)
=> "3.141593"
irb(main):002:0> format('%.f', Math::PI)
=> "3"
irb(main):003:0> format('%.1f', Math::PI)
=> "3.1"
irb(main):004:0> format('%.5f', Math::PI)
=> "3.14159"
irb(main):005:0> format('%5f', Math::PI)
=> "3.141593"
```
上記の`%f`の例では、一番最初と最後の出力が同じですね。
一応こちらを説明すると、最後の`%5f`は**最小幅**を指定しているにすぎないためです。


#**format('%010d', 数値)とは**
もうお分かりですね。これは、**数値（n）をformatメソッドで桁数を10に揃えている**ということになります(10進数表現)。

```
$ irb
irb(main):001:0> n = 7
=> 7
irb(main):002:0> format('%010d', n)
=> "0000000007"
```

#**おわりに**
formatメソッドって素晴らしいですね。
知っているか知らないかで考えつくアルゴリズムが変わってくるのではと感じました。
時折、復習したいと思います。

Rails, Rubyに関していくつか記事をまとめてますので、[takuyaninのマイページ](https://qiita.com/takuyanin)もご訪問ください。

少しでも役に立ったいう方は、いいね、お願いします(^^)