パスワードを忘れた? アカウント作成
602219 journal

umqの日記: バイト列に意味はあるのか(03) 4

日記 by umq

前回,多バイト文字の表し方を,主に日本語文字集合に着目して調べた。

今回は,最近増えつつある Unicode 表現について,まとめてみる。
Unicode そのものについては,詳細への言及を避け,主にバイト列としてどのような形になるかというところに話題の中心をおく。

Unicode の現行バージョンでは,コードポイントが,U+0000U+10FFFF の範囲に 1,114,112 個用意されている。

コードポイントは,基本的に文字単位で割り振られるが,既存の文字コードとの関係等で同一文字の異なる字体に対してコードポイントが割当てられる場合がある。
これらをうまく扱うための一般的な仕組みは,まだ,存在しない。Unicode の仕組み上は,同一の内容に対する異なる表現がある場合,それらを「正規化」することで表現を統一できるようにしている。「正規形」とよばれるこの形式は,文字の分解の度合い等で4種類ある。文字列の検索等を試みる場合は,いずれかの正規形に変換して表現を絞り込むか,検索ロジック中で可能性のある異なる表現での試行を実装する等の工夫が必要になるかもしれない。

Unicode 文字列をバイト表現するにあたって,何種類かの符号化方式から,用途にあったものを選択する。主な符号化方式として UTF-8, UTF-16, UTF-7, UTF-32 などがある。
それぞれの特徴を列挙してみる。
なお,Unicode としては,コードポイントの範囲が U+0000U+10FFFF に限られるので,表現可能な範囲と必ずしも一致しないことを記しておく。

  • UTF-32
    最も,コードポイントの対応のわかりやすい符号化方式。0x000000000xFFFFFFFF で(現在未定義のものを含めて)多くのコードポイントを表現可能。処理系によってバイト順が異なる場合がある。先頭に BOM(Byte Order Mark: U+FEFF) をつけて,バイト順を示す場合もある。
    現在は,恐らく,教科書等以外ではまぁ見かけないのではないだろうか。
  • UTF-16
    U+0000U+D7FF, U+E000U+FFFF はそのまま 0x00000xFFFF の対応する値で表現する。
    U+10000U+10FFFF については,コードポイントの値から 0x10000 を減じたもの(二進数表現で xxxx xxxxxxyy yyyyyyyy)を,10bits ずつ上下にわけ,それぞれに 0xD800, 0xDC00 を加えて上位側から順に 110110xxxxxxxxxx 110111yyyyyyyyyy というふうに並べる。この対を surrogate pair と呼ぶ。
  • UTF-8
    コードポイントの値を二進数表現したものを分割し,以下のいずれかのうち元も少ないバイト数で表現できる方法をとる。
    • U+0000-U+007F : 0xxxxxxx
    • U+0080-U+07FF : 110xxxxx 10xxxxxx
    • U+0800-U+FFFF : 1110xxxx 10xxxxxx 10xxxxxx
    • U+10000-U+1FFFFF : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    • U+200000-U+3FFFFFF : 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    • U+4000000-U+7FFFFFFF : 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

    バイトパターンに合致しつつも,より少ないバイト数で表現可能な場合は,不正な文字として取り除く必要があることに留意が必要。

  • UTF-7
    少々複雑なエンコード方法なので,使われる機会はこれからは減っていくかもしれない。
    この符号化方式では,7bit で符号化可能な文字のみで表現することが大きな特徴で,``+'' と ``-'' で変則 base64 エンコードで変換した文字列を挟む。
    詳細については,別途資料をあたって欲しい。
  • UTF-9
    扱いにくそうなので,恐らく,日の目を見ることはなさそうだが,こういうのもある(あった)。コードポイント範囲と二進数表現の対応を以下に示す。
    • U+0000-U+007F : 0xxxxxxx
    • U+00A0-U+00BF : 101xxxxx
    • U+00C0-U+00FF : 11xxxxxx
    • U+0100-U+07FF : 1000xxxx 1xxxxxxx
    • U+0800-U+FFFF : 100100xx 1xxxxxxx 1xxxxxxx
    • U+10000-U+7FFFFF : 100101xx 1xxxxxxx 1xxxxxxx 1xxxxxxx
    • U+800000-7FFFFFFF : 10011xxx 1xxxxxxx 1xxxxxxx 1xxxxxxx 1xxxxxxx

U+0080-U+009F に対応する表現がないのが特徴。
UTF-8 に比べて,ちょっとだけデータサイズが小さくなる,かな。

UTF-16 や UTF-32 は,いかなるバイト値もとりうるので,``printable'' であるかそうでないか,の区別は文字が割当てられているかどうかによってのみ可能となる。
UTF-8 や UTF-9 は,バイト列に特徴があるため,バイト列の特徴でおおよその判別が可能になる。
UTF-7 については,7bit の範囲で表現されるため,UTF-7 であることの判別を別にすれば従来と何ら変わりない方法で文字列を切り出すことができよう。

参考

[ひとつまえ]

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
typodupeerror

Stay hungry, Stay foolish. -- Steven Paul Jobs

読み込み中...