Python では、
ファイル冒頭に "encoding: shift_jis"
等の記述を行うことで、
ソースファイルの文字コードを指定することが出来ます。
#!/bin/env python # encoding: shift_jis label = '日本語'
これで一見動いているように見えるのですが、 それをもって「マルチバイト文字が使えている」 と安心していると咬まれます。
「ソースファイルの文字コード指定が可能」であることから、 てっきり「適切な内部表現形式をもったオブジェクトに変換」 してくれるものとばかり思っていたのですが、 Python では「バイト列ベースの文字列」と「Unicode 文字列」は、 そもそも異なるクラスとして定義されており、 文字列は通常「バイト列ベースの文字列」 オブジェクトとしてインスタンシエーションされます。
そして、 「バイト列ベースの文字列」オブジェクトに、 非 ASCII 文字に相当するバイト(列)が検出された場合、 文字列操作関数やフォーマット機能は上手く機能しません。
UnicodeDecodeError: 'ascii' codec can't decode byte XXX...
エラー条件をきれいに抽出できなかったので、 エラーメッセージ例を掲載しておきますが、 この「概ね動くが特定のバイト列の組み合わせで不意に動かなくなる」 という振る舞いが、 この症状で一番厄介なところです (条件抽出に成功された方は、ご一報頂ければ幸いです)。
この問題を回避するには、
「Unicode 文字列」オブジェクトとして
文字列オブジェクトをインスタンシエーションする必要があり、
それは文字列リテラルに対して前置詞的に
"u" を付与することで行います。
% python
> print type('あ')
<type 'str'>
> print type(u'あ')
<type 'unicode'>
また、 「バイト列ベースの文字列」 オブジェクトとしてインスタンシエーションされるのは、 何もソース中の文字列に限った話ではなく、 ファイル等の入力から生成された文字列オブジェクトも、 基本的には「バイト列ベースの文字列」です。
入力文字列の「Unicode 文字列」オブジェクト化は、 以下のように行います。
import codecs # 標準入力を使用する場合: sys.stdin = codecs.getreader('shift_jis')(sys.stdin) # 直接ファイルを開く場合: file = codecs.open(filename, 'r', 'shift_jis')
ちなみに、 「Unicode 文字列」オブジェクト化とは関係ありませんが、 標準出力(ないし標準エラー出力) に対して特定のエンコーディングを指定する場合は、 以下のような処理を行います
sys.stdout = codecs.getwriter('shift_jis')(sys.stdout)