漢詩詩語集を処理するに際して,Excel ファイルを CSV に一括変換するツール『Excel 一括 CSV』だと,JIS X 0212 のいわゆる JIS 第三・第四水準の文字の出力が「?」に化けてしまった。これをなんとかしたいと思い別のツールをいろいろ漁ってみたが,これというものが見当たらなかった。UNIX 系システムでの Excel ファイルのテキスト変換では,xlhtml というプログラムが昔から有名であるが,これとて日本語の扱いに関しては不十分なところがある。
この調査の過程で,Windows でなくても動作する Perl Excel ファイルハンドリング・モジュール Spreadsheet::
Excel は古いバージョンで作成したものだと,ファイル内の日本語文字コードが Shift_JIS なのか CP932 なのか UCS2 なのかよくわからない。おまけに私の目的として,出力すべきファイルは UTF-8 エンコードでなければならない。Spreadsheet::
ただし,Spreadsheet::
今回作成した Excel ワークシート一括 CSV 変換プログラム xlstocsv.pl を以下に掲げる。こんなに短いコードでできてしまうのなら,最初から自分の手を動かすべきであった。同じ課題をもつ方は必ずいらっしゃると思うので,以下のコードをコピって活用いただきたい。もちろん無保証,無サポートである。使い方は,コマンドラインで xlstocsv.pl 対象Excelファイル とする。引数に Excel ファイルを一つ指定する。すべてのワークシートが単一 CSV テキストストリームとして STDOUT に書き出される。ファイルに格納したいのならリダイレクトする。
#!/usr/bin/perl -w # -*- coding: utf-8; mode: cperl; -*- # Excel to CSV use strict; use utf8; use Spreadsheet::ParseExcel; use Spreadsheet::ParseExcel::FmtJapan; binmode STDOUT, ":utf8"; binmode STDERR, ":utf8"; ($#ARGV < 0) && die "Usage: $0 xls-file\n"; my $fnm = $ARGV[0]; # Excel file name my $ct = 0; # 出力行数 # Excel object my $xls = Spreadsheet::ParseExcel->new(); my $fmt = Spreadsheet::ParseExcel::FmtJapan->new(); # 日本語あり my $bko = $xls->parse($fnm, $fmt); # Excel Book object my @wsa = $bko->worksheets(); # Worksheet object 配列 utf8::decode($fnm); # ワークシート毎の処理 foreach my $ws (@wsa) { my $wsnm = $ws->{"Name"}; my $mxrow = $ws->{"MaxRow"}; my $mxcol = $ws->{"MaxCol"}; print STDERR "*** $0 $fnm - sheet: $wsnm start.\n"; if ((defined $mxrow) && (defined $mxcol)) { # 行毎の処理 for (my $row = 0; $row <= $mxrow; $row++) { my $line = ""; # 列毎の処理 for (my $col = 0; $col <= $mxcol; $col++) { # セル値をセット my $cell = $ws->get_cell($row, $col); $line .= $cell->value() if (defined $cell); $line .= ","; } print "$line\n"; $ct++; } } } print STDERR "*** $0 from $fnm wrote $ct lines\n";
もしワークシート毎にファイルをばらしたいのなら,foreach my $ws (@wsa) のブロック(ワークシート単位のループ)部分の始めと終わりに独自ファイル処理(「ファイル名+シート名」でファイルハンドルを割り当てる等)を入れればよい。また,このコードは CSV をカンマ区切り形式とし,かつセルの内容に半角カンマが含まれない前提である。もし半角カンマが含まれてもよいようにするなら,得られたセル値を出力時にダブルクォーテーションマークで括る,等の処置を施していただきたい。
これで,一つの Excel ファイルに夥しいワークシートがあろうが,いちいち Excel を開いて CVS として保存しなくても,コマンドラインから一発で CSV 変換ができるようになった。おまけに FreeBSD でも Linux でも Mac OS X でも動くのである。もちろん Windows でも動くし,Excel がインストールされていなくても Excel ファイルを処理出来る,というメリットがある。
私の課題 — いただいた詩語集の処理に関しては,71 の Excel ファイルそれぞれに何十ものワークシートがあって,Excel をひとつひとつ開いてワークシート毎に CSV エクスポートするのはとてもやっていられないが,xlstocsv.pl を使えば次のコマンド操作だけで二字詩語,三字詩語の CSV(2c.csv, 3c.csv)をまとめることができた。
% foreach i (2c-xls/*.xls) foreach? set BS=`basename $i .xls` foreach? (xlstocsv $i > 2c-$BS.csv) >& 2c-$BS.err foreach? end % foreach i (3c-xls/*.xls) foreach? set BS=`basename $i .xls` foreach? (xlstocsv $i > 3c-$BS.csv) >& 3c-$BS.err foreach? end % env LC_ALL=C sort 2c-*.csv | uniq > 2c.csv % env LC_ALL=C sort 3c-*.csv | uniq > 3c.csv
xlstocsv.pl は引数に Excel ファイルを一つしか指定できないが,複数の Excel ファイルを扱いたいなら,上の tcsh 操作のようにループで回せばよい。次のシェルスクリプトは,カレントディレクトリにあるすべての Excel ファイルを,「xls と同じファイルベース名+拡張子 csv」という名の CSV ファイルに書き出す。
#!/bin/sh for i in *.xls do BS=`basename $i .xls` xlstocsv.pl $BS.xls > $BS.csv done[ 2020/06/02 付記 ]
上記において「JIS X 0212 文字もうまく処理でき,かつ UTF-8 で出力できる」と書いた。しかしながら,その後,Unicode コードポイント U+20000 以上の拡張エリアの CJK 統合漢字の場合,文字化けしてしまうことが判明した。
この問題を解決するため,Python 言語,Pandas モジュールを用いて Excel 2007 から CSV を抽出するプログラムを書いた。これについては『Python 言語による Excel - CSV 相互変換プログラム』に記したので,そちらも参考にしていただきたい。