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