7.1 文字列とUnicode
この章では、Pythonでデータを自在に操るためのテクニックを学びます。まずは、最も身近なデータである「文字列(テキストデータ)」について深く掘り下げていきましょう。
7.1.1 Unicode
Section titled “7.1.1 Unicode”かつてコンピュータの世界では、英語のアルファベットや数字、一部の記号しか扱えない「ASCII(アスキー)」という文字コードが使われていました。 しかし、世界中の様々な言語(日本語やヨーロッパの言語など)や記号(絵文字など)を扱うためにはASCIIでは不十分です。そこで登場したのが、世界のすべての文字と記号に一意の番号を割り当てる国際標準**「Unicode(ユニコード)」**です。
Python 3のUnicode文字列
Section titled “Python 3のUnicode文字列”Python 2では単なる「バイト列」と「Unicode文字列」が混在していましたが、Python 3の文字列はすべてUnicode文字列として扱われます。
Pythonの文字列内で特定のUnicode文字を指定するには、いくつかの方法があります。
\u+ 4桁の16進数: 基本多言語面(一般的な文字)を指定します。\U+ 8桁の16進数: より上位の面(絵文字など)を指定します。\N{name}: 標準のUnicode文字名を直接指定します。
import unicodedata
# 1. コードで指定(ユーロ記号)print('\u20ac') # €
# 2. コードで指定(雪だるまマーク)print('\u2603') # ☃
# 3. 名前で指定place = 'caf\N{LATIN SMALL LETTER E WITH ACUTE}'print(place) # café
# unicodedataモジュールを使って、名前から文字を引くことも可能print(unicodedata.lookup('LATIN SMALL LETTER E WITH ACUTE')) # éUTF-8によるエンコードとデコード
Section titled “UTF-8によるエンコードとデコード”Pythonプログラムの内部ではUnicodeとして扱われますが、ファイルに保存したり、ネットワーク経由でデータをやり取りしたりする場合は、文字を「バイト列(0と1のデータ)」に変換する必要があります。 この変換ルールとして最も広く使われているのがUTF-8です。
エンコーディング(文字列 $\rightarrow$ バイト列)
Section titled “エンコーディング(文字列 $\rightarrow$ バイト列)”文字列をバイト列に変換するには encode() メソッドを使います。
snowman = '\u2603'print(len(snowman)) # 1文字
# UTF-8でエンコードしてバイト列にするds = snowman.encode('utf-8')
print(ds) # b'\xe2\x98\x83' (bで始まるのはバイト列であることを示す)print(len(ds)) # 3バイト使われていることがわかるもし、サポートされていないエンコーディング(例:ASCII)で変換しようとするとエラーになりますが、第2引数を指定することでエラーを回避(無視や置換)することもできます。
# ASCIIでエンコードしようとするとエラーになる文字の場合# snowman.encode('ascii') -> UnicodeEncodeError
# エラーを無視するprint(snowman.encode('ascii', 'ignore')) # b''
# '?' に置き換えるprint(snowman.encode('ascii', 'replace')) # b'?'デコーディング(バイト列 $\rightarrow$ 文字列)
Section titled “デコーディング(バイト列 $\rightarrow$ 文字列)”外部から取得したバイト列をPythonの文字列に戻すには decode() メソッドを使います。このとき、エンコードされたときと同じ方式(UTF-8など)を指定しなければ正しく復元できません。
place = 'café'place_bytes = place.encode('utf-8')print(place_bytes) # b'caf\xc3\xa9'
# 正しい方式(UTF-8)でデコードplace2 = place_bytes.decode('utf-8')print(place2) # café
# 間違った方式(ASCIIなど)でデコードしようとするとエラーや文字化けが起きる# place_bytes.decode('ascii') -> UnicodeDecodeError# place_bytes.decode('latin-1') -> 'cafÃO' (文字化け)