【Python】Unicode / UTF-16 エスケープシーケンス文字列 から 文字 に変換する方法

みんな大好き絵文字「👍」で。


👉 GitHub Emoji Unicode Full Emoji List - shortcode | code point | escape-sequence hatena-bookmark

 

👍 Unicode エスケープシーケンス


s = '\\U0001f44d'  # r'\U0001f44d'

print(s)
# \U0001f44d

print(s.encode().decode('unicode-escape'))
# 👍

print(eval(f'"{s}"').encode().decode('unicode-escape'))
# ð

「Unicode エスケープシーケンス」から「文字」に変換するには、


'\\U0001f44d'.encode().decode('unicode-escape')

でいけます。

 

👍 UTF-16 エスケープシーケンス

同様に、


s = '\\ud83d\\udc4d'  # r'\ud83d\udc4d'

print(s)
# \ud83d\udc4d

print(s.encode('utf-16', 'surrogatepass').decode('utf-16'))
# \ud83d\udc4d

print(eval(f'"{s}"').encode('utf-16', 'surrogatepass').decode('utf-16'))
# 👍

「UTF-16 エスケープシーケンス」から「文字」に変換するには、


eval('"\\ud83d\\udc4d"').encode('utf-16', 'surrogatepass').decode('utf-16')

でいけます。

 

👍 まとめ

ややこしいです。他にいい方法ないかな。



【Unicode】UTF-16 サロゲートぺア と コードポイント の変換

UTF-16 は、Unicode の文字をコードポイントと呼ばれる整数値で表現するエンコーディング方式です。UTF-16 では、一部のUnicode 文字は16ビットでは表現できないため、サロゲートペアと呼ばれる特殊な方法で符号化されます。

サロゲートペアは、2つの16ビットの値(上位サロゲートと下位サロゲート)を組み合わせて1つの Unicode 文字を表現します。上位サロゲートは 0xD800-0xDBFF の範囲にあり、下位サロゲートは 0xDC00-0xDFFF の範囲にあります。

Wikipedia で調べると数式があります。

【Unicode】UTF-16 サロゲートぺア と コードポイント の変換
👉 Unicode - Wikipedia hatena-bookmark


code-point <-> surrogate-pair

これに合わせて Python コードにしてみました。


def cp_to_sp(cp):
    cp -= 0x10000
    hsg = cp // 0x400 + 0xD800
    lsg = cp % 0x400 + 0xDC00
    return hsg, lsg


def sp_to_cp(hsg, lsg):
    cp = 0x10000 + (hsg - 0xD800) * 0x400 + (lsg - 0xDC00)
    return cp

この関数を、みんな大好き絵文字「👍」で試してみます。


👉 GitHub Emoji Unicode Full Emoji List - shortcode | code point | escape-sequence hatena-bookmark

表にあるデータから、コードポイントとサロゲートペアのそれぞれの値を使います。


cp = 0x1f44d
hsg, lsg = cp_to_sp(cp)
print(hex(hsg), hex(lsg))
# 0xd83d 0xdc4d

hsg = 0xd83d
lsg = 0xdc4d
cp = sp_to_cp(hsg, lsg)
print(hex(cp))
# 0x1f44d

うまくいってます。

 

👍 まとめ

Unicode まわりは CJK のおかげでか、ややこしいことになってます。

UTF-16などのエンコード処理を扱う場合、コード内では「コードポイント」を中心にを進めると幸せになることがよくあります。


👉 Python vs Kotlin Unicode Escape Sequence (エスケープシーケンス) の記述 hatena-bookmark


Python vs Kotlin Unicode Escape Sequence (エスケープシーケンス) の記述

あると便利な気がして Python スクリプトで作成しましたが。

👉 GitHub Emoji Unicode Full Emoji List - shortcode | code point | escape-sequence hatena-bookmark

AndroidStudio や IDEA Intellij では \uXXXX\uXXXX のような絵文字などの「Unicode Escape Sequence (エスケープシーケンス)」の記述をエディタからできますよね。


// Kotlin
println("Hello, world!")
println("\ud83d\udca4")

実行すると意図した絵文字が表示されます。

しかし、Python では、実行ができません。


# Python
print("Hello, world!")
print("\ud83d\udca4")

エラーメッセージは以下。

UnicodeEncodeError: 'utf-8' codec can't encode characters in position 0-1: surrogates not allowed

2つのエスケープシーケンスでそれぞれ試してみます。


💤
\U0001f4a4
\ud83d\udca4


// Kotlin    
    
// Illegal escape: '\U'
// println("\U0001f4a4")

// OK    
println("\ud83d\udca4")


# Python

# OK
print("\U0001f4a4")

# UnicodeEncodeError:
# 'utf-8' codec can't encode characters in position 0-1: surrogates not allowed
print("\ud83d\udca4")

 

😄 まとめ

エスケープシーケンスをコードに記述する場合、


Kotlin:
"\uXXXX\uXXXX"

Python:
"\UXXXXXXXX"

を使うと良い。

それぞれ、桁数(X)は、4桁、8桁で固定。
足りなければ、0 でパディング。