あらすじ
基本 json で返す web api を csv 形式で出力することになりました。 フロント側で format を csv に変換する仕組みを導入したとろこ Windows の Excel で不具合が発生します。 ということで CSV という拡張子の TSV を UTF-16LE で返すエンドポイントを作成することになりました。
- http://qiita.com/mashiro/items/0d0b9bbb0f4a6cca620c
- http://stackoverflow.com/questions/6588068/which-encoding-opens-csv-files-correctly-with-excel-on-both-mac-and-windows
何が何だかわかりませんが言われた通りに作業する事にします。
開発環境
% python --version Python 2.7.3
余談
Python2 では str 型と unicode 型が混在します。
# -*- coding: utf-8 -*- print type('あいうえお') # <type 'str'> print type(u'あいうえお') # <type 'unicode'>
そして str 型も unicode 型のいずれも encode, decode という関数が使えます。
# -*- coding: utf-8 -*- print type('あいうえお'.decode('utf_8')) # <type 'unicode'> print type(u'あいうえお'.decode('utf_8')) # <type 'unicode'> print type('あいうえお'.encode('utf_8')) # <type 'str'> print type(u'あいうえお'.encode('utf_8')) # <type 'str'>
本題
str 型も unicode 型にも encode, decode という関数が使えるのでを文字コードを変換する処理は以下のように書けます。
# -*- coding: utf-8 -*- print type('あいうえお'.decode('utf_8')) # <type 'unicode'> print type('あいうえお'.encode('utf_8')) # <type 'str'>
さて、ちょっとややこしいのですが今回必要な str 型は以下の条件を満たすものです。
UTF-16LE でエンコードされた str 型で文字列の先頭に UTF-8 の BOM を含む
http://docs.python.jp/2/library/codecs.html#unicode
Microsoft は Notepad プログラム用に UTF-8 の変種 (Python 2.5 では "utf-8-sig" と呼んでいます) を考案しました。まだ Unicode 文字がファイルに書き込まれない前に UTF-8 でエンコードした BOM (バイト列では 0xef, 0xbb, 0xbf のように見えます) を書き込んでしまいます。
というわけで Python2 でこの 先頭に UTF-8 BOM を含む UTF-16LE な文字列は以下のように書くことができます。
# -*- coding: utf-8 -*- import codecs text1 = (codecs.BOM_UTF8 + 'あいうえお').encode('utf_16_le') text2 = 'あいうえお'.encode('utf_8_sig').encode('utf_16_le') print text1 == text2
テストケースなどで上記BOM を削除したい場合は以下のようします。 ポイントは unicode ではなく byte の状態で先頭の BOM 以降を取り出すところです。
# -*- coding: utf-8 -*- import codecs text0 = 'あいうえお' text1 = (codecs.BOM_UTF8 + 'あいうえお').encode('utf_16_le') utf8_text = text1.decode('utf_16_le').encode('utf8') # どちらでも好きなほうで、 print utf8_text[len(codecs.BOM_UTF8):] == text0 print utf8_text[len(bytearray([0xEF, 0XBB, 0XBF])):] == text0
Microsoft Crazy:(