CSVと配列

レコードとフィールド

我々が日常的に利用する「データ」は多くの場合表形式 で2次元の形で表現できる。

たとえば、次のような電話帳データを考える。

漢字氏名 カタカナ氏名 電話番号 メイルアドレスその1 住所

全ての項目が揃った1単位のデータのことをレコード、 レコードの中にあるひとつひとつの項目のことをフィールドという。 この例に従うデータ並びとしては以下のものが考えられる。

公益太郎コウエキタロウ 0234-567-8901koeki@koeki.example.jp魔界
飯森花子イイモリハナコ 0234-567-8902iimori@koeki.example.jp結界

各項目がすべて揃ったものを「レコード」、 漢字氏名やカタカナ氏名などの最小項目単位を 「フィールド」という。表計算ソフトなどでは1レコードを1行に、 1フィールドを1セルに書き込んで表現する。表計算ソフトなどでは データの集合を保存するときにはデフォルトでそのソフト固有の保存形式で 記録している。このため、なんらかのデータを専用ソフトで作成して ファイルに保存したものは、その保存形式に対応したソフトを使わない 限り開くことができない。

これに対し、あらゆる種類のソフトウェアで読み書きできる形式がいくつか ある。 そのうちの一つがCSV形式である。

CSVの構造

複数のフィールドをフィールドごとにカンマ(,)で区切り、 1レコードを1行におさめたテキストファイル形式をCSV形式という(Comma Separated Value)。CSV 形式はアプリケーションに依存しない一般的なデータファイル形式で、 データ処理を行なうプログラムであればほぼ全てのソフトウェアから利用できる。 このため、誰にでも参照してもらいたいデータファイルは CSV 形式にして保存・受け渡しするのが基本である。また、Rubyには CSV ファイルの読み書きを容易に行なえるライブラリがあるため、 「データ入力を表計算ソフトで、計算処理をRubyプログラムで行なう」 といった効率的なデータ処理設計が可能である。

CSV形式は、値をカンマで区切って列挙する。各値は、

ようにする。フィールドに空白文字かカンマを含む文字列が来るときは 必ずダブルクォートで括る。たとえば、

という4つのフィールドをまとめたレコードを CSV で表すときは

Hello,123,"456","Hello, world"

のように記す。なお、文字列自身にダブルクォートが含まれるときは、 ダブルクォートを重ねて表す。たとえば「He said "Hello".」 という文字列は、

"He said ""Hello""."

となる。

RubyのCSVライブラリ

Ruby付属の CSV ライブラリを利用すると、正しく記述された CSV ファイルを一括で読み込むことができる。

CSVファイルの読み込み

CSV ファイルからデータを読むには CSV.read メソッドを使う。

require 'csv'
data = CSV.read(CSVファイル)

簡単なCSVファイルを作ってCSVライブラリから読み込んでみる。 以下のようにして word.csv を作る。

cat > word.csv
bird,2
cat,4
octopus,8
C-d

このようなCSVファイルをCSV.read()で読み込むと:

つまり、『配列の配列』が用意される。

         ↓全体の配列(配列の配列)↓
<--------------------------------------------->
[["bird", "2"], ["cat", "4"], ["octopus", "8"]]
 <----------->  <---------->  <-------------->
 ↑1行目の配列  ↑2行目の配列 ↑3行目の配列

irbを使って読み込む実験をしてみる。

irb
require 'csv'
=> true
tango = CSV.read("word.csv")
=> [["bird", "2"], ["cat", "4"], ["octopus", "8"]]	# 「配列の配列」の形になっている
tango.length
=> 3				# 3行(レコード)なので長さは3
tango[0]
=> ["bird", "2"]		# 第0要素は先頭のレコード(の配列)
tango[0][1]
=> "2"				# 先頭レコードの第1(2つ目)の要素は"2"

このCSVファイルを読み取って、内容を出力するプログラム例を示す。

word-print.rb

#!/usr/koeki/bin/ruby
# -*- coding: utf-8 -*-
require 'csv'

tango = CSV.read("word.csv")

tango.each do |row|		# 1レコードの値の集合が配列でrowに入る
 # rowには [第1列の項目, 第2列の項目] の配列が毎回入る
 printf("[%s]の足は%d本です\n", row[0], row[1].to_i)
end

実行例は以下のとおり。

./word-print.rb
[bird]の足は3本です
[cat]の足は4本です
[octopus]の足は8本です

問題

  1. 以下の内容をword2.csvに保存してから実行すると、 第1列の内容を最初に出力したあと gets で待機し、[Enter] を押すと第2列の内容を出力するプログラム word2.rb を作成せよ。

    花より,団子
    泣きっ面に,蜂
    三度目の,正直
    二度あることは,三度ある
    

    実行例を以下に示す。

    ./word2.rb
    「花より」といえば?: [Enter]
    「団子」です。
    「泣きっ面に」といえば?:  
    
  2. 以下の表の内容を表すCSVファイル tohoku.csv を作成せよ。

    青森県りんご白鳥
    岩手県キジ
    宮城県ミヤギノハギ
    秋田県ふきのとうやまどり
    山形県紅花オシドリ
    福島県ネモトシャクナゲキビタキ
  3. 上のCSVファイルの1行目のレコード(3フィールド)を、 配列の表記で書き表せ。

    答は ruby -r csv -e 'p CSV.read("tohoku.csv")[0]' で得られるのでその前に考えてみよ。

  4. 上の tohoku.csvCSV.read で開き、 以下のように各レコードの内容を出力するプログラム tohoku.rb を作成せよ。

    ./tohoku.rb
    青森県の花はりんご,鳥は白鳥です。
    岩手県の花は桐,鳥はキジです。
    宮城県の花はミヤギノハギ,鳥は雁です。
    秋田県の花はふきのとう,鳥はやまどりです。
    山形県の花は紅花,鳥はオシドリです。
    福島県の花はネモトシャクナゲ,鳥はキビタキです。
    

本日の目次