ExcelでCSVをそのまま開く

ExcelCSVファイルを開くと、0で始まる数値や日付形式と解釈可能なデータが自動変換されてしまい、うっかり保存すると元の情報が失われてしまうことがあります。例えば

sample.csv

001,1/2/3,03-14,01234567890

Excelで開いて保存すると

1,2001/2/3,3月14日,1234567890

となってしまいます。

これに対し、自動変換させずに開く方法としては、テキストインポートウィザードを使う方法が知られていますが、意外と手順が面倒です。
拡張子が.txtの場合はファイルを開くだけで自動的にウィザードが起動するのですが、.csvの場合はいったん.txtにリネームするか、「データ→外部データの取り込み→テキストファイルのインポート」を使って取り込む必要があります*1。前者の拡張子を変更する方法は単純に考えて面倒なだけでなく、エクスプローラの設定で「登録されている拡張子は表示しない」のチェックをはずしておく必要があります。一方、後者のデータインポートの方法だとフィールドにインポート属性が付いてしまうので、ウィザードの途中でプロパティを変更して属性を付かないようにする手順が増えてしまいます。

VBAでマクロを書けばよさそうなものですが、Excelに記録させてみると以下のようなコードであることがわかります(わかりやすいように主要な部分以外は省略)。

    With ActiveSheet.QueryTables.Add(Connection:= _
        "TEXT;C:\rawcsv\sample.csv", Destination:=Range("A1"))
        .AdjustColumnWidth = True
        .TextFileTabDelimiter = True
        .TextFileCommaDelimiter = True
        .TextFileColumnDataTypes = Array(2, 2, 2, 2)
        .Refresh
        .Delete
    End With

ここで問題なのがArray()の部分です。読み込むCSVのカラム数に合わせてそれぞれの形式を指定する(2=文字列のようです)のですが、カラム数は読み込んでからでないとわかりません。1回読み込んでからカラム数を調べて再読み込みするのかな、と思っていたのですが、実は、Excelの最大カラム数=256に合わせて配列を指定すればよいことがわかりました。

VBAだと配列の初期値を一括指定できないので、Forループで代入してやる必要があります。これ、Rubyに慣れた体には大変な苦痛です。なにせArray.new(256, 2)と書けばいいところがDim v(256) As Long, i As Long: For i = 0 To 255: v(i) = 2: Next iこれですから。

そこでRubyの登場ですよ。わあ、強引。

冗談は抜きにしても、VBAで書く場合、マクロはCSV側には保存できませんから、マクロつきのファイルを別に用意するか、アドインにしてやる必要があります。ところが、セキュリティ警告の出方がバージョンによって違うので、他の人に使ってもらおうと思うとドキュメントを書くのも一苦労です。また、アドインの場合、メニューなりツールバーにボタンをつけるなりしてやらないと使いづらいのですが、アドインを使わなくなったときに後始末をするとかなんとかで、とにかく面倒です。面倒なの!

ということで(前置き長すぎ)、VBAを以下のようなコードに書き直します。

rawcsv.rb

require 'excel_lib'

file = ARGV[0]
exit unless file && File.exist?(file)

app = Excel.new
app.displayAlerts = true
begin
  wks = app.workbooks.add.sheets(1)
  qt = wks.queryTables.add(
    'Connection' => "TEXT;#{file}",
    'Destination' => wks.range('A1'))
  qt.adjustColumnWidth = true
  qt.textFileTabDelimiter = true
  qt.textFileCommaDelimiter = true
  qt.textFileColumnDataTypes = Array.new(256, 2)
  qt.refresh
  qt.delete
rescue
  app.quit
end

Excelの制御には以前も紹介した「RubyでExcel」を使っています。site_libあたりにインストールしてください。これをrubyscript2exeで実行形式にします。

rubyscript2exe --rubyscript2exe-rubyw rawcsv.rb c:\sample.csv

できあがったrawcsv.exeか、ショートカットをデスクトップにおいて、そのアイコンに目的のCSVをドラッグ&ドロップするとそのままで開いてくれます。

追記:

よく見たらexcel_libの機能はほとんど使っていませんね。begin以前を以下のようにすれば標準のwin32oleだけで動作するようです。

require 'win32ole'

file = ARGV[0]
exit unless file && File.exist?(file)

app = WIN32OLE.new('Excel.Application')
app.visible = true

追記:Rubyって何?という人向けには、以下に普通のやりかたが書いてあります。

*1:Excel2000の場合。Excel2003では、メニュー名称が違います