Python2における文字列「文字型」と「ユニコード型」についてザックリとまとめた

最近『meya.ai』をいじっていて、Pythonになんちゃって入門しました。

quotto.hatenablog.com

初心者として戸惑ったのが文字列の扱い。

print 'Hello,World'
print u'Hello,World'

「u」ってなんですかね。 ということで、ザックリとまとめてみます。

※独学入門の初心者のため、間違えているところ多数の可能性があります。

注意

私はPython2.7を使っています。 軽く調べたところPython3.x系では全然違うようなので注意してください。

「文字型」と「ユニコード型」

Python2.xにおいては、文字列を表す型に「文字型」(str)と「ユニコード型」(unicode)の2種類が存在します。

「u」が付いていないのが「文字型」、付いているのが「ユニコード型」です。

print type('abcd') #=> <type 'str'>
print type(u'abcd') #=> <type 'unicode'>

何が違うの?

ザックリ言うとこういうこと。

# -*- coding:utf-8 -*-

#これはAsciiなのでどちらも一緒。
print len('abcd') #=> 4
print len(u'abcd') #=> 4

#これはマルチバイト(UTF-8)なので、文字型はバイト数になる。
print len('あいうえ') #=> 12
print len(u'あいうえ') #=> 4

要するにPython2.xでは文字型と言いつつもそれはバイトやでってことです。

で、どっち使えばいいの?

単純に「文字列処理ができるユニコード型を使っておけばいいじゃん」とは思うのですが、やはり注意が必要です。

最たる例が標準出力とファイル出力です。 以下のtest.pyというプログラムを用意します。

# -*- coding:utf-8 -*-

#標準出力
text = u'あいうえお'
print text

#ファイル出力
f = open('test.txt','w')
f.write(text)
f.close()

これをターミナル上で実行すると、ファイル出力がエラーとなります。

$ python test.py
あいうえお
Traceback (most recent call last):
  File "test.py", line 6, in <module>
    f.write(text)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-4: ordinal not in range(128)

なぜか。

実はprint実行時にはPythonが「出力先の文字コードUTF-8だね!」と判断して、UTF-8の文字型に変換してくれているんですね。 標準出力の文字コードはsysオブジェクトに値が格納されておりそいつを基に判定するのだと思います。

# -*- coding:utf-8 -*-
import sys

print sys.stdout.encoding #=> UTF-8

#だからこの値がasciiだとprintもエラーになる。
import codecs
sys.stdout = codecs.getwriter('ascii')(sys.stdout)
print 'あいうえお'
#=>UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-4: ordinal not in range(128)

一方でf.writeでは「文字コードの指定ないからようわからん。asciiでいいやろ。」と考えasciiに変換しようとするのですが、当然日本語には対応できずエラーとなります。

そのためファイル出力を行うにあたっては、

  1. あらかじめユニコード型を文字型にエンコードしておく。
  2. ファイルオープン時にエンコードを指定する。

のどちらかを実施する必要があります。

# -*- coding:utf-8  -*-
import codecs
text = u'あいうえお'

#文字型へエンコード
f = open('test1.txt','w')
f.write(text.encode('utf-8'))
f.close

#エンコードを指定してファイルを開く(要codecsオブジェクト)
f = codecs.open('test2.txt','w','utf-8')
f.write(text)
f.close
$ python test.py
$ cat test1.txt
あいうえお
$ cat test2.txt
あいうえお

結論:入門するならPython3

Python3だとunicode型が無くなり、「文字型とバイト型」というわかりやすい構成になっているようです。 私は何故か2.7で入門してしまいましたが、「u」とかいちいち付けるの面倒なんでこれから始める人は3.x系がおすすめです。

参考にさせていただきました。

私の記事よりも圧倒的に細かく・詳しく書いてあります。
Pythonの日本語処理
http://www.kabipan.com/computer/python/unicode.html
Python2のstr/unicodeとencode/decode