全県の郵便番号CSV(ZIP書庫)ファイルを日本郵便のサイトからダウンロードして、解凍して、SQLiteのテーブルへぶち込む、一連の流れをperl で書いた。
そもそもの発端は、メールフォームや会員登録フォームなどで住所を入力する手間を省くため郵便番号から自動的に住所が挿入される、よくある仕組みを実装するため、変換のベースとなるCSVデータをSQLiteにインポートすれば、SELECT一発で引けるやん、という訳。
ここで、上記のCSV => SQLite にインポートするため、Text::CSV_XSモジュールを使った。まぁ、それが当然ですよね。このスクリプト自体はすぐ出来たんですが、作成・実行をWindows7上のActivePerl 5.14.1 で行った。なんら問題ない。
#CSVからレコードを読込データベーステーブルに登録する。 # $dbh :DBIハンドル, # $table :テーブル名 # $fin :CSVファイルのIOハンドル # utf8,h2z_,sjis は 文字コード変換のために定義した関数 # eval_result はエラー処理のために定義した関数 sub csv2db { my ($dbh,$tablename,$fin) = @_; my $csv = Text::CSV_XS->new({binary => 1,eol => $/}); eval { my $sth = $dbh->prepare(sprintf('insert into %s values(?,?,?,?,?,?,?,?,?)',$tablename)); $dbh->begin_work; my $count = 1; while(my $row_ = $csv->getline($fin)) { $row_->[1] =~ s/\s+$//g; if(1 != $sth->execute($row_->[0], $row_->[1], $row_->[2], utf8(h2z_($row_->[3],'cp932')), utf8(h2z_($row_->[4],'cp932')), utf8(h2z_($row_->[5],'cp932')), utf8($row_->[6]), utf8($row_->[7]), utf8($row_->[8]))) { print "failed to insert...row($count)\n"; } if((my $c = $count++) % 10000 == 0) { $dbh->commit; print sjis("${c}件登録されました。\n"); $dbh->begin_work; } } }; eval_result('insert data successfully.',sub{$dbh->commit;},sub{$dbh->rollback;}); }
で、このコードを含む一連のスクリプトを、テストサーバー(CentOS6 / perl 5.10 ) で実行すると・・・
Wide character in subroutine entry…
でました・・・。やな、メッセージ(;゚ロ゚)
半角カタカナから全角カタカナの変換がおかしいのかなー・・・なんて見当違いな事をいろいろ試してました。というのも、ちゃんと変換できてるレコードもあるので・・・。ちゃんとSQLiteへインポートできたレコードと上記エラーメッセージが出たレコードを比較しても全然分からん。
で、最終的に、分かったのが・・・CSVからレコード配列に変換するときに変なことが起こってるみたい・・・というのが判明して、Text::CSV_XSモジュールを使わず単純にsplitを使うと、あっけなくインポート終了。なぜ???
最終的に、Text::CSV_XSのバージョンが違っていたことが原因と判明。
Windows上のActivePerlにバンドルされていたバージョンは、”0.82″。 CentOS上のperlにバンドルされていたバージョンは”1.19″。どうやら新しい方のバージョンは、Text::CSV_XS->new({…, decode_utf8 => 0})というようにdecode_utf8属性?を無効にしないと、UTF8フラグが付いてしまう?らしい。この辺、まだよく分からん。
こんな、perldoc Text::CSV_XS をちゃんと読めば解決できたであろう、しょーもないことに丸2日もかかっちまったよ。トホホ。。。