それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

python で日本語のUnicode のコードポイントから平仮名を連番テーブルを作る

python でA-Zみたいに 「ひらがな」をコードポイントで扱う。

f:id:takuya_1st:20190414152203p:plain

tl;dr

>>> [ chr( i+ 0x3042) for i in range(0,85)]
['あ', 'ぃ', 'い', 'ぅ', 'う', 'ぇ', 'え', 'ぉ', 'お', 'か', 'が', 'き', 'ぎ', 'く', 'ぐ', 'け', 'げ', 'こ', 'ご', 'さ', 'ざ', 'し', 'じ', 'す', 'ず', 'せ', 'ぜ', 'そ', 'ぞ', 'た', 'だ', 'ち', 'ぢ', 'っ', 'つ', 'づ', 'て', 'で', 'と', 'ど', 'な', 'に', 'ぬ', 'ね', 'の', 'は', 'ば', 'ぱ', 'ひ', 'び', 'ぴ', 'ふ', 'ぶ', 'ぷ', 'へ', 'べ', 'ぺ', 'ほ', 'ぼ', 'ぽ', 'ま', 'み', 'む', 'め', 'も', 'ゃ', 'や', 'ゅ', 'ゆ', 'ょ', 'よ', 'ら', 'り', 'る', 'れ', 'ろ', 'ゎ', 'わ', 'ゐ', 'ゑ', 'を', 'ん', 'ゔ', 'ゕ', 'ゖ']

解説

chr ( 0x3042 )

これは、以下と同じ

'\u3042'

\u でユニコードにコードポイントであることを示している。

'\u3042'を示したときに、Pythonで内部エンコーディングにデコードされ文字列として格納されている。

文字符号化方式UTF-8/UTF-16エンコードすると、次のようなバイト列になる。

>>> '\u3042'.encode('utf-8')
b'\xe3\x81\x82'
>>> '\u3042'.encode('utf-16')
b'\xff\xfeB0'

ちなみに、内部エンコーディングは次のように確認できる(いまはUTF-8固定かな?たしか)

import sys; sys.getdefaultencoding()

得られたバイト列を、文字列にする

>>> b'\xe3\x81\x82'.decode()
'あ'

ちなみに b'\xxxx' はバイト列であることを示す b です。

UTF-16のバイト列をそのままデコードしてもエラーになります。

>>> b'\xff\xfeB0'.decode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte

内部エンコーディングUTF-8(デフォルト)なので、UTF-16UTF-8としてデコードしようとしてエラーですね。

>>> b'\xff\xfeB0'.decode('utf16')
'あ'

これで、バイト列がUTF-16の符号化として扱われて、デコードされ、Unicodeのコードポイントを得ることが出来て、内部エンコーディング(この場合UTF-8)にデコードされ出力された。

ユニコードのコードポイントを連番で扱う。

あ=0x3042 であることを利用して連番「ひらがな」を作ってみる。

>>> [chr(0x3042+i) for i in range(0,10)]
['あ', 'ぃ', 'い', 'ぅ', 'う', 'ぇ', 'え', 'ぉ', 'お', 'か']

逆に、「あいうえお」をすべてユニコードのコードポイントにしてみる

>>> [ (ord(i)) for i in  "あいうえお"]
[12354, 12356, 12358, 12360, 12362]

見やすいように16進数 Hexにする

>>> [ hex(ord(i)) for i in  "あいうえお"]
['0x3042', '0x3044', '0x3046', '0x3048', '0x304a']

まとめ

chr でユニコードのコードポイント(数字)から、文字へ

>>> chr( 0x3042 )
'あ'
>>> chr( 0x3042 + 1  )
'ぃ'

ord で、文字を数字(int)へ。hex で16進数表記へ

>>> ord('あ')
12354
>>> hex(ord('あ'))
'0x3042'

補足

ユニコードUnicode)のコードポイントは、文字符号の変換表(数字→文字)であり、utf-8utf-16 はその変換した数字をバイナリとしてどうやって保存するかになる。

ユニコードでは、あ=0x3042 である。これはUTF-8でもUTF-16 でも変わらない。ただし、この0x304 をどうやって0/1に落とし込むかで表現方法は変わる。