search
LoginSignup
20

More than 5 years have passed since last update.

posted at

updated at

Python 3 での Unicode に関する備忘録

Unicode 文字の名前を取得する

unicodedata.name() を使用する。

>>> import unicodedata

>>> unicodedata.name('s')
'LATIN SMALL LETTER S'
>>> unicodedata.name('す')
'HIRAGANA LETTER SU'
>>> unicodedata.name('🍣')
'SUSHI'
>>> unicodedata.name('🍣🍣')
TypeError: name() argument 1 must be a unicode character, not str

名前から Unicode 文字を取得する

unicodedata.lookup() を使用する。

>>> import unicodedata

>>> unicodedata.lookup('LATIN SMALL LETTER S')
's'
>>> unicodedata.lookup('HIRAGANA LETTER SU')
'す'
>>> unicodedata.lookup('SUSHI')
'🍣'
>>> unicodedata.lookup('SUSI')
KeyError: "undefined character name 'SUSI'"

また \N{名前} というエスケープシーケンスを使用して Unicode 文字を指定することもできる。

>>> '\N{SUSHI}'
'🍣'
>>> '\N{SUSI}'
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 0-7: unknown Unicode character name

Unicode 文字のエスケープシーケンスを取得する

str.encode() を使用する。第 1 引数には unicode-escape を指定する。

>>> 's'.encode('unicode-escape')
b's'
>>> 'す'.encode('unicode-escape')
b'\\u3059'
>>> '🍣'.encode('unicode-escape')
b'\\U0001f363'

返り値は bytes 型である。ここでエスケープシーケンスについて補足説明する。

\u について

\u3059 のように \u の後ろに 4 個の 16 進数が続くエスケープシーケンスは、基本多言語面 のいずれかに含まれる文字に該当する。最初の 2 桁が面番号を、後半の 2 桁がその面の中でのインデックスを表す。

\U について

\U0001f363 のように \U の後ろに 8 個の 16 進数が続くエスケープシーケンスは、基本多言語面より上位の面に位置する文字に該当する。なお左端の数字は必ず 0 である。

文字列の len について

>>> type('🍣')
<class 'str'>
>>> len('🍣')
1
>>> len('\U0001f363')
1
>>> len('寿司')
2

Unicode 文字列の長さは文字数を表す。

対して str.encode() の返り値は bytes 型なので、長さはバイト数を表す。

>>> import binascii

>>> encoded = '🍣'.encode('unicode-escape')
>>> encoded
b'\\U0001f363'
>>> type(encoded)
<class 'bytes'>
>>> len(encoded)
10
>>> binascii.b2a_hex(encoded)
b'5c553030303166333633'  # 16 進数に変換するとたしかに 10 バイト

>>> '🍣'.encode('UTF-8')
b'\xf0\x9f\x8d\xa3'  # 4 バイト
>>> len('🍣'.encode('UTF-8'))
4

Unicode 正規化

任意の形式で 正規化 するには unicodedata.normalize() を使用する。第 1 引数に正規化形式を指定する。

>>> import unicodedata

>>> po = 'ポ'
>>> po_nfc = unicodedata.normalize('NFC', po)
>>> po_nfc 
'ポ'
>>> po_nfd = unicodedata.normalize('NFD', po)
>>> po_nfd
'ポ'
>>> po_nfc == po_nfd
False
>>> len(po_nfc)
1
>>> len(po_nfd)
2

>>> unicodedata.normalize('NFD', 'ポ') == unicodedata.normalize('NFKD', 'ポ')
True
>>> unicodedata.normalize('NFC', 'ポ') == unicodedata.normalize('NFKC', 'ポ')
True

>>> unicodedata.decomposition('ポ')  # decomposition() は分解マッピングを返す。
'30DB 309A'
>>> 'ポ' == unicodedata.normalize('NFC', '\u30DB\u309A')
True

参考

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
20