UTF-16 は、Unicode の文字をコードポイントと呼ばれる整数値で表現するエンコーディング方式です。UTF-16 では、一部のUnicode 文字は16ビットでは表現できないため、サロゲートペアと呼ばれる特殊な方法で符号化されます。
サロゲートペアは、2つの16ビットの値(上位サロゲートと下位サロゲート)を組み合わせて1つの Unicode 文字を表現します。上位サロゲートは 0xD800-0xDBFF の範囲にあり、下位サロゲートは 0xDC00-0xDFFF の範囲にあります。
Wikipedia で調べると数式があります。
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
表にあるデータから、コードポイントとサロゲートペアのそれぞれの値を使います。
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などのエンコード処理を扱う場合、コード内では「コードポイント」を中心にを進めると幸せになることがよくあります。
【Kotlin】絵文字を含む Unicode 文字列の文字数をカウントする方法と文字ごとの構成 https://t.co/Ge1cKTLiSn #unicode #programming #kotlin #android
— chanzmao (@maochanz) May 29, 2023
【Python】絵文字を含む Unicode 文字列の文字数をカウントする方法と文字ごとの構成要素 https://t.co/oNKbGFeHyk #プログラミング #Python
— chanzmao (@maochanz) May 29, 2023
GitHub Emoji Unicode Full Emoji List - shortcode | code point | escape-sequence
👉 https://t.co/o4cKi20TwW#emoji #unicode #プログラミング #python #swift #kotlin— chanzmao (@maochanz) May 21, 2023