ちょっと必要があって,複数の CSV テキストファイルからデータをこれに対応するワークシートに格納して,Microsoft Excel ブックファイルを生成する Perl プログラム csvtoxls.pl を書いた。かつて,書籍情報の Excel ファイルを読んでジャンル毎の CSV ファイルに分解し,ここから SQLite3 リレーショナルデータベースを作成するプログラムを書いたのだが,ちょうどこの逆を行うプログラムである。Microsoft Excel といっても,Office 2003 までのブック形式を生成するものである(私は個人的に Office 2003 しか所有していない)。
csvtoxls.pl 処理概要
プログラムの引数に,4 つの CSV テキストファイルのベース名と生成すべき Excel ファイル名をとるものとする。CSV ファイルベース名はそのまま Excel シート名に設定するものとする。入力する CSV テキストファイルは引数で指定した名称に拡張子 .txt を付加したものとする。例えば,% ./csvtoxls.pl genre_0 genre_1 genre_2 genre_3 genre_4 gen.xls
として起動すると,次を順次行う。
Spreadsheet::WriteExcel モジュール
Excel データ出力には Perl モジュール Spreadsheet::
CSV データの各項目を Excel 表として生成するのに限れば,一般的に処理の流れとしては以下のようになるだろう。
- Excel book オブジェクトを生成する。
my $xlsbook = Spreadsheet::WriteExcel->new("Excelファイル名");
- ワークシートオブジェクトを生成する。
my $xlsws = $xlsbook->add_worksheet("ワークシート名");
- 必要に応じ,セルの書式を設定する。書式はフォントや罫線など多様に設定出来るようになっている。
my $cellfmt = $xlsbook->add_format(); $cellfmt->set_align('left');
- 必要に応じ,列の幅を設定する。「開始列」から「終了列」の範囲で設定するインタフェースである。いちばん左の列は列 0 とする。“B:F”(B列からF列まで)というような指定も可能である。
$xlsws->set_column(開始列, 終了列, 幅);
- ワークシートのセルに値を格納する。セル書式指定($cellfmt)の指定は任意である。
$xlsws->write(行, 列, データ, $cellfmt);
行,列 は第 1 行,第 1 列のセルの位置をそれぞれ 0 とする数値である。write メソッドは標準的なもので,テキストデータ用の write_ string,数値用の write_ number などのデータ属性に応じたメソッドが用意されている。 - すべての出力処理が完了したらブックオブジェクトをクローズする。
$xlsbook->close;
日本語は UTF-8 の場合,とくに意識しなくてよい。Windows 機種依存文字を扱うならば,
$xlsws->write(行, 列, decode("cp932", "データ"));
Spreadsheet::
Perl コード
csvtoxls.pl コードを以下に掲載する。上記処理概略に対し,Excel 文書プロパティの設定も行っている。私の必要性から,入力 CSV の DOS 行末形式の行末コード(\r: CR + \n: LF)を削除していたり,CSV のセパレータが “|” であったりと,少しローカルな処理が入ってはいるけれども,複数の CSV をそれぞれのワークシートに格納し,ひとつの Excel ブックを生成する例として参考になればと思う。
#!/usr/bin/perl -w # -*- coding: utf-8; mode: cperl; -*- # csvtoxls.pl: Excel Book generator from CSV # - usage: csvtoxls.pl sht1 sht2 sht3 sht4 sht5 xls # sht1-5: シート名, CSVファイルのベース名(拡張子 .txt 前提) # xls: 出力 xls ファイル名 # - CSVフォーマット(セパレータ '|'): # 0対象外|1題|2副題|3著者|4刊行月|5ISBN|6価格|7刊行状態|8画像|9コメント # 2015(c) isao yasuda, All Rights Reserved. # $Id: csvtoxls.pl 121 2015-09-23 08:20:56Z isao $ use strict; use utf8; use SpreadSheet::WriteExcel; binmode(STDERR, ":utf8"); # コマンドライン引数が 6(@ARGV 最大配列番号が 5)でなければ usage を出力して終了 ($#ARGV == 5) || die "Usage: $0 sht1 sht2 sht3 sht4 sht5 xls\n" . " sht1-5: Worksheet name, CSV file basename (without .txt)\n" . " xls: Excel file name\n"; # Excel book オブジェクトの生成 my $xlsfl = $ARGV[5]; # Excel ファイル名 my $xlsbook = Spreadsheet::WriteExcel->new($xlsfl); # 文書プロパティ設定 $xlsbook->set_properties( title => '書籍管理データベース', author => 'isao yasuda', comments => '最新書籍データベースから逆生成', ); # セルフォーマット設定 # - 水平: left; 垂直: top; 折返し表示: on; my $cellfmt = $xlsbook->add_format(); $cellfmt->set_text_wrap(); $cellfmt->set_align('left'); $cellfmt->set_align('top'); # CSVファイル毎の処理 for (my $i = 0; $i < 5; $i++) { # CSV file open my $sn = $ARGV[$i]; open(CI, "<:utf8", "$sn.txt") || die "* $0 open failed $sn.txt: $!\n"; # 引数の文字列のシート名で Excel worksheet を生成する my $xlsws = $xlsbook->add_worksheet($sn); # ワークシート列幅の個別設定 $xlsws->set_column(1, 1, 14); # col 1: タイトル to 14 $xlsws->set_column(3, 3, 10); # col 3: 著者名 to 10 $xlsws->set_column(5, 5, 17); # col 5: ISBN to 17 $xlsws->set_column(8, 8, 20); # col 8: 画像ファイル名 to 20 $xlsws->set_column(9, 9, 50); # col 9: コメント(説明文) to 50 my $icnt = 0; # CSV入力行カウンタ my $rp = 0; # シート行ポインタ # テーブルヘッダ出力 $xlsws->write_string($rp, 0, "対象外"); $xlsws->write_string($rp, 1, "タイトル"); $xlsws->write_string($rp, 2, "副題"); $xlsws->write_string($rp, 3, "著者名"); $xlsws->write_string($rp, 4, "刊行月"); $xlsws->write_string($rp, 5, "ISBN"); $xlsws->write_string($rp, 6, "価格"); $xlsws->write_string($rp, 7, "刊行状態"); $xlsws->write_string($rp, 8, "画像ファイル名"); $xlsws->write_string($rp, 9, "コメント(説明文)"); $rp++; # CSVデータ出力 while (<CI>) { $_ =~ s/\r\n//; # DOS形式行末コードを削除 $icnt++; # CSV カラム分解(セパレータ '|'),カラム数チェック my @col = split(/\|/, $_); ($#col == 9) || die "* $0 $sn.txt csv format illegal.\n"; # Excel シートに格納 for (my $j = 0; $j < 10; $j++) { my $rc; $rc = $xlsws->write_string($rp, $j, $col[$j], $cellfmt); # 非0 でエラー ($rc) && die "* $0 writing error occured. code: $rc ($sn.txt: $icnt)\n"; } $rp++; } close(CI); print STDERR "* $0 sheet $sn normally written $icnt records.\n"; } $xlsbook->close; print STDERR "* $0 normally generated $xlsfl.\n";
実行結果
% ./csvtoxls.pl 0_kushu 1_kashu 2_sonota 3_haidan 4_kadan test.xls * ./csvtoxls.pl sheet 0_kushu normally written 117 records. * ./csvtoxls.pl sheet 1_kashu normally written 92 records. * ./csvtoxls.pl sheet 2_sonota normally written 93 records. * ./csvtoxls.pl sheet 3_haidan normally written 10 records. * ./csvtoxls.pl sheet 4_kadan normally written 9 records. * ./csvtoxls.pl normally generated test.xls.
生成された Excel を開いた状態は下図のとおり。プログラムのなかで行ったセルの書式設定により,セル表示が「水平左寄せ」,「垂直上端揃え」,「折り返して全体を表示オン」となっている。列の幅もきちんと設定されている。
図 1. 生成された Excel ブック