Ruby TIPS
ファイルから1行/段落ごと読み込む(入力する)には?
Rubyでテキストファイルから文字列を読み込むための方法として、ファイル内の全テキスト内容を先頭から1行単位ずつもしくは1段落ずつループ処理する方法と、ファイルから読み込んだ全ての行を配列として返す方法を説明する。
前々回の「ファイルから文字列を読み込む(入力する)には?(基本編)」では、Rubyでテキストファイルから文字列を読み込むための基本的な方法を解説し、さらにファイル操作をブロックで記述する方法や、読み込み専用モードでファイルを開く方法、文字コードの基本的な取り扱い方を見た。
前回の「ファイルから1文字ずつ読み込む(入力する)には?」および今回ではその続編として、さまざまな単位でファイルの内容を読み込むメソッドを見ていく。今回は1行ずつ読み込む方法と段落ごと読み込む方法を見ていこう。
ファイル入出力の基本 − 入力編
ファイルから1行ずつ読み込む ― getsメソッド、readlineメソッド
1行ずつの読み込みには、gets
メソッドまたはreadline
メソッドを使う。この2つのメソッドの働きは、基本的には同じだが、ファイルの末尾に達したときにgets
メソッドがnilを返し、readline
メソッドがEOFError
を発生させるという点だけが異なる。考え方は、前回説明したgetc
/readchar
メソッドとほぼ同じなので、プログラム例(リスト1.7)と実行例(実行例1.7)だけを示しておこう。ちなみに、リスト1.7のコードでreadline
を試したい場合は、単純に「gets」を「readline」に置換するだけでよい。
File.open("data001.txt"){|f|
p f.gets # 1行目
p f.gets # 2行目
p f.gets # 3行目
}
|
ファイルに含まれる行数が3行より少ない場合、gets
メソッドではnilが返されるので、読み込めなかった行数だけnilが表示される。readline
メソッドでは、ファイルの末尾以降の行を読み込もうとした時点でEOFError
エラーとなる。
$ ruby sample007.rb
"青龍\n"
"朱雀\n"
"白虎\n"
|
テキストモードでファイルを開いているので、改行文字がLF
、CR
、CRLF
のいずれであってもLF
として取り扱われる。
全ての行を1行ずつ読み込む(ブロックを利用) ― each_lineメソッド、foreachメソッド
全ての行を1行ずつ読み込むには、each_line
メソッドやforeach
メソッドが使える。
each_lineメソッド
まず、each_line
メソッドからプログラム例と実行例を見ていこう。
each_line
メソッドは、ファイルから1行ずつ読み込み、ブロックパラメーターに読み込んだ行を渡す。
File.open("data001.txt", mode = "rt"){|f|
f.each_line{|line|
p line
}
}
|
単純に1行ずつ読み込み、その行を表示する。この例では、読み込まれた行はブロックパラメーターのline
に渡される。
実行例は以下の通り。
$ ruby sample008.rb
"青龍\n"
"朱雀\n"
"白虎\n"
"玄武"
|
ファイルに含まれる行が1行ずつ表示された。行をそのまま出力するなら、リスト1.8のp
メソッドの代わりにprint
メソッドを使えばよい。なお、このファイルの末尾には改行文字は入力されていない。行末の改行文字を削除するなら、リスト1.8のline
をline.chomp
とすればよい。
foreachメソッド
ファイルの内容を1行ずつ読み込むには、File
クラス(厳密にはその継承元であるIO
クラス)の特異メソッドであるforeach
メソッドも使える。
foreach
メソッドはeach_line
メソッドとほぼ同じ機能だが、File
クラスの特異メソッドであるので、前述のリスト1.8のようにFile.open
メソッドのブロックパラメーターからメソッド呼び出しをするのではなく、直接、File.foreach
という呼び出しになることに注意。このため、リスト1.8と同じ処理を行うのであれば、以下のようにより簡単に書けるというメリットもあるが、open
メソッドと違って文字コードやアクセスモードは指定できない(読み込みのみに使える)というデメリットもある。
File.foreach("data001.txt"){|line|
p line
}
|
実行結果は実行例1.8と同じなので省略する。
段落ごとに読み込む
ここまでに説明してきたgets
/readline
/each_line
メソッドでは、改行文字としてどの文字を使うかをそれぞれの引数rs
に指定できる。改行文字として引数rs
にnilを指定すると「改行なし」と見なされる。一方、空文字列(""
)を指定すれば連続する改行が行の区切りと見なされるので、連続する改行を段落として取り扱うようなときに便利である。
以下は段落を扱うプログラム例と実行例である。
f = File.open("data002.txt", mode = "rt"){|f|
f.each_line(rs=""){|line|
p line.chomp(rs="")
}
}
|
each_line
メソッドの引数rs
に空文字列を指定しているので、連続した改行文字が行の区切りとなる。なお、読み込んだ行の最後には改行文字が付けられたままなので、chomp
メソッドで行末の改行文字を取り除いている。chomp
メソッドでも、改行文字として空文字列を指定すると連続する改行文字が取り除かれる。
$ more data002.txt
これが第一段落です。
段落と段落の間は改行文字2つで区切られています。
したがって、この行と
この行は同じ段落になります。
$ ruby sample010.rb
"これが第一段落です。"
"段落と段落の間は改行文字2つで区切られています。"
"したがって、この行と\nこの行は同じ段落になります。"
|
最初に、このプログラムで読み出すdata002.txt
ファイルの内容を確認しておく。段落は3つ。最後の2行は途中で改行されているが、改行文字は1つしか入っていないので、同じ段落と見なされる。
ファイルから読み込んだ行を配列として返す ― readlinesメソッド
ファイルから1行ずつ読み込むのに使われるreadline
メソッドと名前の似たreadlines
メソッドも利用できる(リスト1.11)。ただし、readlines
メソッドは、読み込んだ行を配列として返す。
s = []
File.open("data001.txt", mode = "rt"){|f|
s = f.readlines
}
p s
|
readlines
メソッドに引数を指定しなければ、全ての行が読み込まれ、配列として返される。引数limit
を指定すると、指定したバイト数だけ読み込まれる。
実行例は以下の通り。
$ ruby sample011.rb
["青龍\n", "朱雀\n", "白虎\n", "玄武"]
|
ファイルの全ての行が配列として返された。行の末尾にある改行文字は削除されずに返されることに注意。
readlines
メソッドでは、行の末尾にある改行文字も返されてしまう。改行文字を取り除きたければ、gets
/getline
/each_line
/foreach
メソッドのいずれかにより1行ずつ読み込んで、chomp
メソッドで改行文字を削除して配列に追加するとよい。具体的にはリスト1.12のようなコードになる。
s = []
File.foreach("data001.txt"){|line|
s << line.chomp
}
p s
|
<<
は配列に要素を追加するメソッド。chomp
メソッドを使って文字列の末尾にある改行文字を削除する。
実行例は以下の通り。
$ ruby sample012.rb
["青龍", "朱雀", "白虎", "玄武"]
|
改行文字が削除されたので、各行の内容だけが配列に追加された。実行例1.11と比べてみるとよい。
まとめ
gets
メソッドとreadline
メソッドは1行読み込むのに使う。each_line
メソッドやFile
クラスの特異メソッドであるforeach
メソッドでは、読み込んだ各行を、ブロックを使って処理できる。readlines
メソッドは、読み込んだ行を配列として返す。
API:IOクラス|Fileクラス カテゴリ:組み込みライブラリ
API:getsメソッド|readlineメソッド|each_lineメソッド|foreachメソッド|readlinesメソッド カテゴリ:IOクラス
※以下では、本稿の前後を合わせて5回分(第19回~第23回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
19. ファイルから文字列を読み込む(入力する)には?(基本編)
テキストファイルから文字列を読み込むための基礎を解説。ファイル操作をブロックで記述する方法や、ファイルを開く際に「テキスト読み出し専用モード」でアクセスしたり文字コードを指定したりする方法、BOM付きファイルを処理する方法を説明する。
20. ファイルから1文字ずつ読み込む(入力する)には?
Rubyでテキストファイルから文字列を読み込むための方法として、ファイルから1文字単位で文字を取得する方法と、ファイル内の全テキスト内容を先頭から1文字ずつループ処理する方法を説明する。
21. 【現在、表示中】≫ ファイルから1行/段落ごと読み込む(入力する)には?
Rubyでテキストファイルから文字列を読み込むための方法として、ファイル内の全テキスト内容を先頭から1行単位ずつもしくは1段落ずつループ処理する方法と、ファイルから読み込んだ全ての行を配列として返す方法を説明する。
22. ファイルに文字列を書き込む(出力する)には?
テキストファイルに文字列を書き込むための基本を解説。新規書き込みと追加の方法を確認した後、任意の位置から書き込む方法や読み書き両用モードでファイルを利用する方法を説明する。
23. ファイルの排他制御を行うには? その際のデッドロック問題とは?
1つのファイルに複数のプログラムから同時アクセスすると、上書きによりデータが消失する可能性がある。これを回避するために排他制御を行う方法と、その際に問題となるデッドロックを回避する方法について説明する。