Rubyで、以下のようなタブ区切りのテキストファイル(foo.txt)を読み込み、CSVファイル(bar.csv)として書き出す際にタイトルのような疑問が出たので調べてみた。
(foo.txt)
john m 18
pau",l m 20
alice f 15
カラム名もつけて、わかりやすくテーブルにするとこんな感じ。
Name | Sex | Age |
---|---|---|
john | m | 18 |
pau",l | m | 20 |
alice | f | 15 |
以下のRubyスクリプトでテキストファイルをCSVファイルに変換してみると...
require 'csv'
input = 'foo.txt'
output = 'bar.csv'
people = []
person = []
File.open(input) do |f|
f.each_line do |l|
person = l.chomp.split(sep = "\t")
people << person
end
end
CSV.open(output, "w", :force_quotes => true) do |csv|
people.each do |per|
csv << per
end
end
CSVファイル、なんかpau",l
のu
と,
の間でダブルクォーテーション(")が増えてない??
(bar.csv)
"john","m","18"
"pau"",l","m","20"
"alice","f","15"
CSVの仕様(本記事に関係する事項)
CSV形式とは、テキストデータをいくつかのフィールド(項目)に分け、区切り文字であるカンマ「,」で区切ったデータ形式。
例を挙げるとこんな感じ(CRLFは改行)。各レコード(行)でフィールドがカンマで区切られている。
日本国,東京,127767944 CRLF
アメリカ合衆国,ワシントン,300007997 CRLF
…
フィールドはダブルクォート「"」で囲んでも囲まなくてもよくて、次の3つのレコードは(CSVの文字列としては)同じ内容。
日本国,東京,127767944 CRLF
"日本国","東京","127767944" CRLF
"日本国","東京",127767944 CRLF
フィールドの値がダブルクォートを含む場合は?
フィールドがカンマ、ダブルクォート、改行を含む場合は、必ずダブルクォートで囲み、
フィールドに含まれるダブルクォートは2つ並べて("")エスケープする。
レコードの内容が「日本[改行]国」「"東京"」「127,767,944」のときはこうする。
"日本 CRLF
国","""東京""","127,767,944" CRLF
ダブルクォートが増えたのはエスケープするため
"john","m","18"
"pau"",l","m","20"
"alice","f","15"
pau",l
は"pau"",l"
とすることで、CSVファイル内で1つのフィールド値として認識されるのでした。
参考
CSV (Wikipedia)
Common Format and MIME Type for Comma-Separated Values (CSV) Files