文字コード
このレッスンでできるようになること。encoding を明示して、日本語を含む家計簿データを文字化けさせずに保存できるようになります。
ここまで open には毎回 encoding="utf-8" を付けてきました。今回はその理由を確かめます。
ファイルの中身は、突き詰めると 0 と 1 の並び、つまりバイト列です。「コーヒー豆」という文字をどのバイト列に対応させるかという取り決めが文字コード (エンコーディング) です。日本語を書き表す方式は1つではなく、現在の標準である UTF-8 のほかに、日本の業務システムで長く使われてきた Shift_JIS があります。同じ文字でも、方式が違えばバイト列が違います。
そのため、書いたときと違う方式で読むと文字化けするか、そもそも読めずにエラーになります。表計算ソフトから出した CSV が文字化けするという定番の事故は、ほぼこれです。
with open("data.csv", "w", encoding="utf-8") as f:
f.write("コーヒー豆,980\n")
with open("data.csv", encoding="utf-8") as f:
print(f.read())encoding を省くと、Python はその環境の既定の方式を使います。手元では動いたのにサーバーへ置いたら壊れた、という差が出るのはこのためです。読むときも書くときも必ず encoding を書く、と決めてしまうのが一番安全です。
バイト列を直接見たいときは、モードに "rb" を付けて開きます。返ってくるのは文字列ではなく bytes です。bytes を文字列に直すのが decode、文字列を bytes に直すのが encode で、どちらも方式の名前を渡します。方式が食い違うと UnicodeDecodeError になります。
古いシステムに合わせて Shift_JIS で書き出さないといけないこともあります。そのときは encoding="shift_jis" を指定します。方式が変わればバイト数も変わり、UTF-8 の日本語1文字は3バイト、Shift_JIS では2バイトになります。
要件
- text を kakeibo_utf8.csv に encoding="utf-8" で、kakeibo_sjis.csv に encoding="shift_jis" で書く
- 両方のファイルをモード "rb" で開いてバイト列として読む
- 2つのバイト数を空白区切りで1行に表示する
- kakeibo_sjis.csv を encoding="shift_jis" で開いて、中身を strip して表示する
- Shift_JIS のバイト列を utf-8 として decode し、UnicodeDecodeError を except で捕まえて「文字コードが違うと読めません」と表示する
入出力例
出力: "20 15
コーヒー豆,980
文字コードが違うと読めません
"