Rubyによるデータ処理

TSVファイルをCSVファイルに

タブ区切り(TSV,Tab-Separated Values)テキストを読んでCSV(Comma-Separated Values)にして出力する。簡易版であり,元のデータにコンマが含まれているとまずい。1行目の -w はwarningをonにするオプションであるが,/usr/bin/env と組み合わせると,環境によってはうまくいかない。その場合は -w を取るか,あるいは #! /usr/bin/ruby -w のようにフルパスにする。2行目は省略可。

#! /usr/bin/env ruby -w
# coding: utf-8

while line = gets
  puts line.split("\t").join(",")
end

タブ("\t")を区切りとして配列に分割し,それを再びコンマ(",")で結合している。実は,line には改行も付いているので,最後の要素には改行が付く。puts は通常は改行付きで出力するが,すでに改行があれば改行を繰り返さないので,これでうまくいく。個々の要素を操作する必要がある場合には,linechomp して改行を取り除いてから操作する。したがって,ループの中は次のようにしても同じである。

    puts line.chomp.split("\t").join(",")

個々の要素の前後の空白や改行を削除するには strip を使う:

  puts line.split("\t").each { |x| x.strip! }.join(",")

あるいはもっとコンサイスに次のようにもできる:

  puts line.split("\t").map(&:strip).join(",")

ところでExcelはBOM(EF BB BFの3バイト)が頭に付いていないとUTF-8だと認識しない(SJISだと思われてしまう)。BOMを付けるには while ... の前に

print "\xef\xbb\xbf"

を入れる。

以上は標準入力から読み込んだが,ファイル名を指定する場合は次のようにする:

File.open("test.txt", "r") do |f|
  while line = f.gets
    puts line.split("\t").join(",")
  end
end

CSVファイルをTSVファイルに

上と逆に,CSVを読んでTSVを出力するには,上と同様にして "\t""," を逆にすればいいが,CSVはデータ作法にも書いたように少しややこしいルールがあり,それに従って読み書きするために,ここではRubyのCSVクラスを使う。例えばCSVファイルをタブ区切りテキスト(TSV)に直すには次のようにする:

#! /usr/bin/env ruby -w

require 'csv'

CSV(STDIN).each do |row|
  puts row.join("\t")
end

STDIN は標準入力を表す定数である。変数 $stdin も初期値として STDIN が入っているので,こちらを使ってもよい。

ファイル名を指定する場合は次のようにする:

CSV.foreach("test.csv") do |row|

BOM付きUTF-8の場合は,最初の要素にBOMが付いたままになる(見えないが文字数を調べれば1文字分増える)。数値の場合は文字列として読まれるので "123" を読んだつもりで "123".to_f として数値 123 が得られると思ったら,"[BOM]123".to_f だったので 0 になるといった事故がありうる。BOMのありなしにかかわらずBOMを取り払って読むには次のようにする:

File.open("test.csv", "r:BOM|UTF-8") do |f|
  CSV(f).each do |row|
    puts row.join("\t")
  end
end

または

CSV.open("test.csv", "r:BOM|UTF-8").each do |row|
  puts row.join("\t")
end