はじめに
Elixirで標準入出力を扱う際には通常ElixirのIOモジュールを使うことが多いと思います。
Erlangにもioモジュールがあります。というかこっちが本家です。
ElixirのIOモジュールの中でErlangのioモジュールが利用されているのです。例えば、ElixirのIO.puts/2はErlangのio.put_chars/2を使って実装されています。
IO.puts("元氣があればなんでもできる")
:io.put_chars(:standard_io, [~c"元氣があればなんでもできる", ?\n])
io:format/2
Erlangにしかないものとしてio:format/2が興味深いです。
io:format/2を使うといろんな型のデータに対してフォーマットを整えて印字できます。
文字列を直接渡すことができます。Erlangの文字列は「整数(0〜255)のリスト」ですのでそこに注意が必要です。
s
で文字列を整えることができます。
# 5文字だけ印字
iex> :io.format("~5s~n", ["hello world"])
hello
:ok
# 5文字の範囲で右よせ
iex> :io.format("|~5s|~n", ["123"])
| 123|
:ok
# 5文字の範囲で左よせ
iex> :io.format("|~-5s|~n", ["123"])
|123 |
:ok
s
で多バイトの文字に対応するためにはUnicode translation modifier(t
)を指定する必要があります。
# 何もしないと多バイトの文字が文字化け
iex> :io.format("~s~n", ["闘魂"])
é
:ok
# Unicode translation modifierをつけて一件落着
iex> :io.format("~ts~n", ["闘魂"])
闘魂
:ok
f
で浮動小数点数を整えることができます。初期設定では小数点以下6桁が印字されます。
iex> :io.format("~f seconds~n", [30.99])
30.990000 seconds
:ok
iex> :io.format("~.3f seconds~n", [30.99])
30.990 seconds
:ok
p
で何でも印字。リスト要素のコードがErlangのコードとして印字される感じでややこしいです。
文字列専用のs
を使ったほうがよさそうです。
# タプル
iex> :io.format("~p~n", [{1, 2, 3}])
{1,2,3}
:ok
# マップ
iex> :io.format("~p~n", [%{id: 123, name: "Inoki"}])
#{id => 123,name => <<"Inoki">>}
:ok
# 数字
iex> :io.format("~p~n", [123])
123
:ok
iex> :io.format("~p~n", [123.45])
123.45
:ok
# 文字列
iex> :io.format("~p~n", [~c"hello"])
"hello"
:ok
iex> :io.format("~p~n", ["hello"])
<<"hello">>
:ok
iex> :io.format("~p~n", [~c"闘魂"])
[38360,39746]
:ok
iex> :io.format("~p~n", ["闘魂"])
<<233,151,152,233,173,130>>
:ok
標準出力に印字せず、フォーマットされた文字列を生成したいだけの場合は、io モジュールの代わりにio_libモジュールを使うといいかもしれません。
iex> :io_lib.format("My number is ~p", [123])
[77, 121, 32, 110, 117, 109, 98, 101, 114, 32, 105, 115, 32, ~c"123"]
iex> :io_lib.format("My number is ~p", [123]) |> IO.puts()
My number is 123
:ok
他にも文字列操作のための関数を提供するstringモジュールがありますが、ElixirのStringモジュールが充実しているのでおそらくElixirで使うことはないのではないでしょうか。
さいごに
本記事は 闘魂Elixir #59 の成果です。ありがとうございます。