前の関連記事:Python: Unicodeのコードポイントと文字列の変換
文字列→utf-8エンコーディング→16進数表示→バイト列→文字列
In [1]:
# 文字列をutf-8エンコーディングのバイト列にする。
# Unicode文字は\xエスケープで2桁ずつ16進数で表示される。
# バイト列内で2桁の16進数のASCII文字コードに一致する部分はASCII文字で表示される。
u8 = '3日Sun.'.encode()
u8
Out[1]:
ASCII文字のutf-8エンコーディングはASCII文字コードと一致するのでASCII文字でない文字だけ2桁の16進数で表示されています。
In [2]:
# バイト列を16進数表示の文字列にする。ASCII文字もすべて16進数表示になる。
h = u8.hex()
h
Out[2]:
In [3]:
# 16進数表示の文字列をバイト列に変換する。
# bytesは組み込みクラスでfromhex()はクラスメソッド、
b = bytes.fromhex(h)
b
Out[3]:
In [4]:
# バイト列をutf-8として文字列にデコードする。
b.decode()
Out[4]:
文字列→utf-16エンコーディング→16進数表示→バイト列→文字列
In [5]:
# 文字列をutf-16エンコーディングのバイト列にする。
# バイト列内で2桁の16進数のASCII文字コードに一致する部分はASCII文字で表示される。
u16 = '3日Sun.'.encode("utf-16")
u16
Out[5]:
\xの次に2桁の16進数が続くはずですが、バイト列だとASCII文字コードに一致してしまうとASCII文字で表示されます。
正確な16進数表示をみたいときはhex()メソッドで16進数にしないといけません。
In [6]:
# バイト列を16進数表示の文字列にする。
h = u16.hex()
h
Out[6]:
In [7]:
# 16進数の文字列をバイト列に変換する。
# bytesは組み込みクラスでfromhex()はクラスメソッド。
b = bytes.fromhex(h)
b
Out[7]:
In [8]:
# バイト列をutf-16として文字列にデコードする。
b.decode("utf-16")
Out[8]:
サロゲートペアのコードポイントを取得する
サロゲートペアというのはUnicodeが16ビット(4桁の16進数、2バイト)から拡張するときに、16ビットを前提としたシステムへの影響を最小限にするために考えだされたものだそうです(Unicode - Wikipedia)。
なので、サロゲートペアは2桁の16進数を2つ組み合わせたものになっています。
Pythonではエスケープ\Uを使えば32ビット(8桁の16進数)のコードポイントが扱えるのでサロゲートペアを使う必要がありません。
サロゲートペアのコードポイントしかわからないときは、それを8桁の16進数のコードポイントに変換する必要があります。
Pythonではエスケープ\Uを使えば32ビット(8桁の16進数)のコードポイントが扱えるのでサロゲートペアを使う必要がありません。
サロゲートペアのコードポイントしかわからないときは、それを8桁の16進数のコードポイントに変換する必要があります。
In [9]:
s = "\ud83d\ude4f" # サロゲートペアのUnicodeリテラル。
s
Out[9]:
Pythonでは、サロゲートペアのUnicodeリテラルは文字に変換されないのでこれを文字に変換されるUnicodeリテラルにします。
In [10]:
# surrogatepassエラーハンドラをつけてutf-16でバイト列にエンコードする。
b = s.encode('utf-16', 'surrogatepass')
b
Out[10]:
In [11]:
d = b.decode('utf-16') # utf-16として文字列にデコードする。
d
Out[11]:
これでサロゲートペアの文字が表示されるようになりました。
In [12]:
print(d.encode('unicode_escape').decode()) # 文字列をUnicodeリテラルにする。
これでこのサロゲートペアのコードポイントがU+1F64Fとわかりました。
In [13]:
u = "\U0001F64F" # \Uでエスケープして8桁の16進数のUnicodeリテラルにする。
u
Out[13]:
utf-8やutf-32のエンコーディングでもsurrogatepassエラーハンドラが使えますが、utf-16以外ではうまく文字列にデコードできませんでした。
In [14]:
"\uD83C\uDF1F".encode('utf-16', 'surrogatepass').decode('utf-16')
Out[14]:
これで1行でサロゲートペアを文字列にできます。
print("\uD83C\uDF1F".encode('utf-16', 'surrogatepass').decode('utf-16').encode('unicode_escape').decode())
これで8桁の16進数のコードポイントを取得できます。
print("\uD83C\uDF1F".encode('utf-16', 'surrogatepass').decode('utf-16').encode('unicode_escape').decode())
これで8桁の16進数のコードポイントを取得できます。
ノーブレークスペースを、Unicodeリテラル→文字→utf-8エンコーディング→16進数→バイト列→文字、に変換する。
In [15]:
# ノーブレークスペースのコードポイントはU+00A0
# ノーブレークスペースはグリフ(文字)がないので\xエスケープで16進数が表示される。
u = "\u00A0"
u
Out[15]:
In [16]:
# utf-8エンコーディングでバイト列にする。
u8 = u.encode()
u8
Out[16]:
In [17]:
# バイト列を16進数表示の文字列にする。
h = u8.hex()
h
Out[17]:
In [18]:
# 16進数表示の文字列をバイト列にする。
b = bytes.fromhex(h)
b
Out[18]:
In [19]:
# バイト列をutf-8としてデコードして文字列にする。
s = b.decode()
s
Out[19]:
In [20]:
print(s.encode('unicode_escape').decode())
もとの文字がUnicode文字ではなくASCII文字だけなので\u00a0にはなりませんでした。
ノーブレークスペースはUTF-8の半角スペースには2種類あるででてきたものです。
参考にしたサイト
Unicode - Wikipedia
サロゲートペアは後方互換性のために編み出されたものののようです。
Unicode HOWTO — Python 3.5.3 ドキュメント
PythonでのUnicodeの扱いの解説。
How to work with surrogate pairs in Python? - Stack Overflow
PythonでサロゲートペアをUnicodeリテラルに変換する方法。
0 件のコメント:
コメントを投稿