UGA Boxxx

つぶやきの延長のつもりで、知ったこと思ったこと書いてます

USVとWTF

AssemblyScript が WebAssembly グループから非推奨にされてしまう可能性があるという話で、その前提の話になるUnicodeサロゲートの話を聞く機会があったが全くわからなかったので自分なりに復習してみた

Unicodeとかサロゲートペアは以前調べてたが、特にサロゲートペアをつくるときにでてくるビッグエンディアンとかがわからなかった

uga-box.hatenablog.com

Unicode

世界中の文字に2バイトの文字コード(符号化文字集合:文字の集合に符号を対応づけたもの)を割り当てて文字の表現を統一しようと作成された(1991年にv1.0リリース)

2バイトなので、65,536通り(U+0000~U+FFFF)の文字が表現できるが、文字を追加するうちに全然足りなくなった

そこでコードポイントを2バイト=16bitから21bit(U+0000~U+10FFFF)に拡張して、約100文字を収録可能にした

追加前と後で名前がついている

  • U+0000~U+FFFF:Basic Multilingual Plane(BMP基本多言語面
  • U+10000〜U+10FFFF:Supplementary Code Points(非BMP

ただ、既にUnicdeは様々な言語で利用されていたので、21bitに拡張されたものを16bitとして扱わなければならない

サロゲートペア

BMPを2つの16bitでエンコードすることにした(UTF-16エンコーディング

具体的には従来のUnicodeで未使用だった0xD800~0xDBFF(1024通り)を「上位サロゲート」、0xDC00~0xDFFF(1024通り)を「下位サロゲート」と規定し、「上位サロゲート+下位サロゲート」の4バイトで文字を表現する

このサロゲートペアの導入により1024×1024=1,048,576字の領域が追加されることになった

エンコーディング

  • UTF-8
    • 8bitを1単位として用いるエンコーディング
    • Unicode符号位置の範囲に応じて、1~4バイトの長さを取る可変長のコード
  • UTF-16
    • 16bitを1単位として用いるエンコーディング
    • BMPの文字については、コードポイントの整数を16ビットで表したビット組合せがそのままUTF-16の値になる
    • BMP以外の文字は、サロゲートペアの組み合わせでBMP以外のコードポイントを表す
    • 16ビットの単位を8ビットのバイト列に直列化する際に、上位・下位どちらの8ビットを先にするかというバイト順の問題が生じる
    • 上位を先にするビッグエンディアンはUTF-16BE、下位を先にするリトルエンディアンはUTF-16LEと呼ばれる
  • UTF-32
    • 32bitを1単位として用いるエンコーディング
    • コードポイントの整数を32ビットで表したビット組合せがそのままUTF-32の値になる固定長のコード

Unicode Scalar Values(USV)

コードポイントからサロゲート領域を除いたもの(文字が割り当てられているコードポイントの集合)

USVにはサロゲート領域を含まないが、UTF-16エンコードするとサロゲートペアが出現する

このとき、概念ではサロゲートペアは上位サロゲートと下位サロゲートのペアになっているはず(well-formed UTF-16

ところが文字列にUTF-16を採用している一部のプログラミング言語では上位サロゲートと下位サロゲートが単独で出現できてしまう

> '𠮷野家'.substring(1)
"\udfb7野家"

つまり、ペアになっていないサロゲート領域のコードユニットを含むUTF-16(ill-formed UTF-16)が存在する可能性がある

これはデコードしてもUSVにならない

WTF-16(WobblyTransformation Format - 16)

ill-formed UTF-16になる(単独のサロゲートを含む)可能性があるエンコーディングの通称

Java, JavaScript, C#などは実際はWTF-16(上記のsubstringの処理のようにill-formed UTF-16が存在できる)

WTFからUTFへの変換はできないので置換されることが多い(REPLACEMENT CHARACTER (U+FFFD))

これがやっかいなので、データのやりとりではWTFは扱わないようにしたいが、DOMやJsonのStoring型、JavaScriptなどはWTFなので、新しいWeb APIやデータ交換で問題になる可能性があるので注意が必要

まとめ

自分なりに咀嚼したらかなり理解できた

AssemblyScriptの話はこのWTF -> USV するとReplacementされる(もしくはエラーになる)よねという話で議論になったことをなんとなく理解した

他参考

https://blog.jxck.io/entries/2017-03-02/unicode-in-javascript.html

https://zenn.dev/sosukesuzuki/articles/d21d69a5914a03