Pythonでprintの結果をリダイレクトする場合に出力のエンコーディングを指定する方法
Java-ja温泉でちょうどエンコーディングの話で盛り上がっていたので@whosaysniに聞いてみた。print文でunicodeオブジェクトを出力しようとすると、出力先のシェルのエンコーディングでバイト列に変換してから出力される。
tmp$ cat > tmp.py print u'\u307b\u3052' tmp$ python tmp.py ほげ
しかし、シェルの側でリダイレクトをしていると、シェルと違ってファイルのエンコーディングは簡単に取得できないので「エンコーディングわかんないから何で出したらいいかわかんないや。中身がasciiだったらそのまま出してもいいか」とasciiに変換しようとして失敗する。
tmp$ python tmp.py > tmp.txt Traceback (most recent call last): File "tmp.py", line 1, in <module> print u'\u307b\u3052' UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
で、その解決方法だけど、そのスクリプトからリダイレクトして書き出すファイルのエンコーディングがutf-8であると仮定できるなら:
import sys, codecs sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
これでOK。試してみよう。
tmp$ cat > tmp.py import sys, codecs sys.stdout = codecs.getwriter('utf-8')(sys.stdout) print u'\u307b\u3052' tmp$ python tmp.py > tmp.txt tmp$ cat tmp.txt ほげ
めでたしめでたし。あと@tokibitoに chardet ってライブラリでエンコーディングの判定ができると教えてもらった。今回のケースには使わないけど必要になることもありそうだから覚えておこう。