たまには技術者らしいことも

PerlでDBのデータを取り出し、その内容を加工してダウンロードするという要件にちょっと苦労したので、記録しておきます。

DBはMTのアンケートフォームの回答が格納されています。エンコードはUTF8。これはmysqlコマンドでcsv形式にでも出力すればいいかと思っていたら、以下の問題にぶち当たりました。

  • into outfileを使おうとしたら、アカウントがファイル出力権限を持っていない。
    ⇒標準出力をperl側で配列に入力することに変更。
  • 標準出力をperlから拾ってみたら文字化けしてる。
    ⇒statusコマンドで確認すると、mysqlクライアントのデフォルト接続文字コードがutf8になっていた。「–default-character-set=utf8」を付けて解決。

次の問題は、スクリプトと元データがUTF8であるのに、substrで指定した「文字数」ではなく「バイト数」で文字が取り出されてしまいます。

Perlの文字列型データには、utf8フラグなるものがあって、これがついているのは内部コード形式であるという扱いになります。フラグのあるデータと無いデータでは文字数カウントや正規表現でのマッチなどに影響が出ます。しかし、フラグ付きの文字を出力すると「Wide character in print」という警告が出ます。

基本的には出力前までは全てのデータ内部コード形式で扱い、出力(printなど)する前に「Encode::encode_utf8」を使ってフラグをはずす必要があるようです。

「use utf8;」という宣言で、スクリプト内の全てのリテラルはフラグ付きで扱われます。

さて、ここまでできたのはいいのですが、ダウンロード時にShift-JISに変換する必要があります。これはデータをエクセルで読むためです。

標準出力のエンコードを変更する「binmode STDOUT,’encoding(cp932)’;」なる指定ができるのですが、今度は「utf8フラグ」が付いている状態でprintに渡さないと、正常なマッピングができないエラーになります。

せっかくprint前に「encode_utf8」でフラグを外しましたが、逆に全ての出力前に「decode_utf8」でフラグ付きに変換。やっとShift-JISでファイルのダウンロードができました。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です