Python
unicode

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

More than 1 year has passed since last update.


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


参考