読者です 読者をやめる 読者になる 読者になる

sos の 作業メモ

プログラミングや英会話学習、マイルや旅行、日常生活など。最近はWebFormなASP.NETのお守りがお仕事です。

日々の生活にhappyをプラスする|ハピタス Gポイント

文字コード超研究 19章 その1

プログラム一般 読書

文字コード「超」研究 改訂第2版

文字コード「超」研究 改訂第2版

前回の続き

19章 Unicode

Microsoft, Apple, Sun Microsystems(当時)等の大企業が中心となって考案し、NGOUnicode Consortiumが制定/管理を行う文字コード系。ISOが管理するISO 10646も、結局Unicodeと同調したため、ISO/IEC 10646Unicodeは同じ物として扱っても構わないらしい。

ISO 10646のUCS-2とUCS-4

制定当初、Unicodeはわずか16bit。 UCS-2も16bitで1バイトの区と1バイトの点で文字を表すように定義されていた。すぐにこれだけでは全ての文字を納められないこととなり、128個(7bit)の群と256(8bit)の面、そしてこれまでのUCS-2という、231ポイントのUCS-4(固定長4バイト)へと拡張された。(のちに、群もなくなり、0x10ffffまでの111万ポイントへと減っている)

Unicodeの対応

UCS-4で対応したISO 10646と異なり、Unicodeは可変長エンコーディングスキームで対応。 UTF-16では、UCS-2の中の2048のサロゲート領域(U+D800 - U+DFFF)を1024x1024のペアで使う事により、追加で220個のポイントを表現できるようにした。

元のUCS-2の(216 - 2048個)とサロゲートの(220個)で、あわせて1,112,064個のポイントとなる。 (UCS-4もこれにあわせて制限がかかった形となった)

Unicodeの面

  • 0面(U+00000 - U+0FFFF) - BMP (Basic Multilingual Plane)
  • 1面(U+10000 - U+1FFFF) - SMP (Supplementary Multilingual Plane)
  • 2面(U+20000 - U+2FFFF) - SIP (Supplementary Ideograph Plane)
  • 3面(U+30000 - U+3FFFF) - TIP (Tertiary Ideographic Plane)
  • 4-13面(U+40000 - U+DFFFF) - 未定義
  • 14面(U+E0000 - U+EFFFF) - SSP(Supplementary Special-purpose Plane)
  • 15-16面(U+F0000 - U+10FFFF) - 外字領域

UCS-4とUTF-16の換算

UTF-16 1個で表せるのは、U+0000 - U+D7FFと U+E000 - U+FFFF、サロゲートペアはUTF-16 2個が必要となる。

上位サロゲートは0xd800、下位サロゲートは0xdc00から始まる(それぞれ下位10bitが変化する)

UCS-4からUTF-16への変換

  1. UCS-4から 0x00010000 を引く
  2. 20ビットを上位10ビットと下位10ビットに分け、それぞれを0xd800と0xdc00に足す。これがサロゲートペアとなる。

UTF-16からUCS-4への変換 1. 上位サロゲートペアの範囲でなければそのまま32bit化 2. サロゲートペアなら、上位サロゲートから0xd800を引き、10ビット左にシフトしたものと、下位サロゲートから0xdc00を引いたものの和に、0x00010000を加える

UTF-16エンディアン

複数のバイトを扱う時には、ビッグエンディアンとリトルエンディアンのどちらを使うかの問題がある。ファイルから読み込む時には、その環境のエンディアンになっている方が効率が良いため、Unicodeでは両方のエンディアンがサポートされている。

BOM

ファイルがどちらの形式かを示すために、ファイルの先頭に印となる字を入れようという規格がある。この印をBOM(Byte Order Mark)と呼び、その文字としてU+FEFFを使う。ファイルが0xfe 0xffで始まっている時はビッグエンディアン、 0xff 0xfeならリトルエンディアンとなる。U+FFFEという文字は存在しないと定義されているので、この判定が可能となる。

UTF-16 / UTF-16LE / UTF-16BE

UTF-8

1〜6バイトの可変長のコード系。asciiは1バイト、ISO 8859ラテン文字は2バイト、ひらがなや漢字は3バイトになる。

USC-4からUTF-8への変換

先頭のバイトの上位ビットの1の数がバイト数を表す(1バイトの時は0)

U+0000 - U+007F (7ビット)

そのまま1バイト

U+0080 - U+07FF (11ビット)

xxx xxyy yyyy 5と6ビットに分割し。110xxxxx 10yyyyyyの2バイトにする

U+800 - U+FFFF (16ビット)

xxxx yyyy yyzz zzzz 4と6と6ビットに分割し、1110xxxx 10yyyyyy 10zzzzzzの3バイトにする

U+10000 - U+1FFFFF (21ビット)

x xxyy yyyy zzzz zzii iiii 3,6,6,6ビットに分割し、 11110xxx 10yyyyyy 10 zzzzzz 10iiiiiiの4バイトにする

冗長なUTF-8

本来1バイトで表現できるものを、2バイト、3バイトにエンコードすることもできるが、これは不正なUTF-8として禁止されている

UTF-8とBOM

ファイルの先頭にBOMをつけられる。U+FEFFなので、1111 1110 1111 1111 -> 1110 1111 1011 1011 1011 1111 で、0xefbbbfとなる。日本では、BOMのないものをUTF-8Nと呼ぶこともある。

UTF-32

単純にUCS-4の下位31ビットを出力したもので、BEとLEがある

UTFのエンコーディングスキーム

UTF-32はあまり使われない。主流はUTF-8のようである。

  • UTF-8
  • UTF-8N BOMなし(おもに日本でそう呼ばれる)
  • UTF-16 BOMあり BE
  • UTF-16 BOMなし BE
  • UTF-16 BOMあり LE
  • UTF-16BE BOM使用不可
  • UTF-16LE BOM使用不可
  • UTF-32 BOMあり BE
  • UTF-32 BOMなし BE
  • UTF-32 BOMあり LE
  • UTF-32 BOMなし LE

まずはUnicodeの成り立ちから。 表音文字でやりとりできる国と違い、日本や中国等はどうしても文字数が増えてしまう点でとても不利。将来、111万字で本当に足りるのかどうかが非常に心配なのだが…

次回へ続く