んなまにのメモ帳

気が向いたときに更新されます。

Ruby 標準入力から複数行読み取りたい

Ruby で標準入力から複数行読み込む方法を調べた。

環境はMac OSX Yosemite バーション 10.10.5
Ruby 2.3.1

読み取りに使えるメソッド

標準入力から読み取るには、$stdinオブジェクトを使う。
$stdinオブジェクトには以下のようなメソッドがある。

  • $stdin.gets
  • $stdin.readline
  • $stdin.readlines
  • $stdin.read


標準入力から1行読み取る場合はgetsやreadlineが使える。
ターミナルを起動してirbで試す。

$ irb
>> $stdin.gets
hoge
=> "hoge\n"
>> $stdin.readline
hoge
=> "hoge\n"

EOF(End Of File)まで複数行読み込みたい場合は、readlinesを使うとEOFまでの行が配列として返って来る。

$ irb
>> $stdin.readlines
hoge
foo
bar
# ここで、Ctrl+Dを入力
=> ["hoge\n", "foo\n", "bar\n"]

ファイルを丸ごと読み取りたい場合は、readを使う。
readに引数として読み取るバイト数を指定すると、指定されたバイト数分を標準入力から読み取る。
バイト数が未指定の場合、EOFまでの読み取った値を文字列で返す。

$ irb
>> $stdin.read
hoge
foo
bar
# ここで、Ctrl+Dを入力
=> "hoge\nfoo\nbar\n"

複数行の読み取り

プログラミングコンテストの問題を解くときとか、別のコマンドの出力を受け取るようなスクリプトを作るときに標準入力から複数行読み取って処理する事が多い。
こういうとき、getsを使った方法を良く見かける。

while line = gets
  line.chomp! # 改行を削除
  print "line = #{line}\n"
end

line = gets で標準入力から1行読み取り変数lineに格納する。whileの条件部分で読み取りと代入が繰り返しごとに実行される。
lineの中身によって次の繰り返しを実行するか判定している。
lineに何かしら入っていれば次の処理が実行され、lineがnilならループから抜けることになる。
getsはEOFを読み取るとnilを返すから、EOFが入力されたときループを抜ける事になる。

上の処理を適当なファイル名で保存して実行すると以下のようになる。

$ ruby standard_input.rb 
hoge
line = hoge
foo
line = foo
bar
line = bar
# ここで、Ctrl+Dを入力

whileを使う方法だと入力の読み取りと処理がくっついてしまい、処理を追加するとコードが読みづらくなっていくので読み取った値が配列で返ってきた方が嬉しい。
readlinesを使えば各行が配列で返って来るが、配列の各要素に改行コードが入って他のメソッドに入力値を渡す事を考えると邪魔くさく感じる。

readとsplitを使うと各行を配列で取り出す事ができ、入力と処理を分けられる。

p $stdin.read.split("\n")

実行すると入力値した行が配列になって返ってくる。

$ ruby standard_input.rb 
hoge
foo
bar
# ここで、Ctrl+Dを入力
["hoge", "foo", "bar"]

いつもwhileで回して改行を排除したものを配列に追加していたけれど、割とシンプルな方法で各行の値をとる事ができた。