UTF16 , UTF8 : Unicodeをファイルに保存する場合の保存方法(バイナリ値)。
[例]=================================================
あ : Unicode値 : 0x3042
は、UTF16なら、
big endian : 0x30 , 0x42
little endian : 0x42 , 0x30
↓変換……したい。
あ : UTF8なら、0xE3 81 82
(UTF8では、仕様上big endian も little endianも関係無い。)
====================================================
(14) UTF-16からUTF-8への文字コード変換
を参考にして変換してみる。(変換表はwikiのUTF-8にもある。)
変換表(実際にはUTF8は4Byte目までしか現在定義されていない。)
+------------------------+-------------------------------------------------------------------+
| UTF16 | UTF8 |
| | 1Byte目 2Byte目 3Byte目 4Byte目 5Byte目 6Byte目 |
+------------------------+-------------------------------------------------------------------+
| 0x00000000~0x0000007F | 0b0XXXXXXX ---------- ---------- ---------- ---------- ---------- |
| 0x00000080~0x000007FF | 0b110XXXXX 0b10XXXXXX ---------- ---------- ---------- ---------- |
| 0x00000800~0x0000FFFF | 0b1110XXXX 0b10XXXXXX 0b10XXXXXX ---------- ---------- ---------- |
| 0x00010000~0x001FFFFF | 0b11110XXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX ---------- ---------- |
| 0x00200000~0x03FFFFFF | 0b111110XX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX ---------- |
| 0x04000000~0x7FFFFFFF | 0b1111110X 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX 0b10XXXXXX |
+------------------------+-------------------------------------------------------------------+
0x3042は、0x00000800~0x0000FFFFの範囲にあるので、
UTF8の1バイト目 は、1110□□□□
UTF8の2バイト目以降は、1 0□□□□□□
このように、1~4Byteの可変長であるUTF8のバイト数が、
1バイト目の先頭から0までの間にある1の数として定義されているようです。
今回の場合は1バイト目に1が3つ立っているので、合計3バイトで「あ」の一文字を表します。
UTF8の1バイト目は、1110□□□□
UTF8の2バイト目は、10□□□□□□
UTF8の3バイト目は、10□□□□□□
この空いている□に0x3042を先頭ビットから代入していきます。
(ただし、下から詰めていき、最後に残った□は零で埋める事になります。)
↓下から詰めていきます。
UTF8 : 1バイト目は、1 1 1 0 □□一一
UTF8 : 2バイト目は、1 0零零零零零一
UTF8 : 3バイト目は、1 0零零零零一零
↓残りの□を零で埋めます。
UTF8 : 1バイト目は、1 1 1 0 〇〇一一
UTF8 : 2バイト目は、1 0零零零零零一
UTF8 : 3バイト目は、1 0零零零零一零
↓整形
UTF8 : 1バイト目は、0b1110 0011 == 0xE3
UTF8 : 2バイト目は、0b1000 0001 == 0x81
UTF8 : 3バイト目は、0b1000 0010 == 0x82
となり、無事UTF8に変換する事ができました。
ところで、UTF16で記録されたUnicodeの文字がサロゲートペアの場合は、
まず、バイナリを前回の逆手順でUnicode値に変換してからUTF8に変換する事になります。
UTF16で保存する時、バイナリの値は、「叱」の場合、
big endian : 0xD8 42 , 0xDF 9F
little endian : 0x42 D8 , 0x9F DF
となります。(エスケープシーケンスで書くと「\ud842\udf9f」)
これを、前回の逆手順で、「叱(Unicode値 : 0x20B9F)」に置き直してから、
今回の手順を適用する必要があります。
前回の逆手順の例
[例]=================================================
叱 : UTF16のエスケープシーケンスは、\uD842\uDF9F
バイナリでは、
big endian : 0xD8 42 , 0xDF 9F
little endian : 0x42 D8 , 0x9F DF
↓変換……したい。
叱 : Unicode値 : 0x20B9F
====================================================
0xD800~0xDBFFの範囲の文字(0b1101 10XX XXXX XXXX (X : 任意))は上位サロゲートの文字で、
0xDC00~0xDFFFの範囲の文字(0b1101 11XX XXXX XXXX (X : 任意))は下位サロゲートの文字と定義されています。
まずは符号を取り除きます。
上位サロゲート : 0xD842 - 0xD800 == 0x0042
下位サロゲート : 0xDF9F - 0xDC00 == 0x039F
0x0042 == 0b0000 0100 0010
0x039F == 0b0011 1001 1111
(16~11Bitは符号ビットなので、)10Bit目までを、単純につなげると、
0b 0001000010 1110011111 == 0x10B9F
最後に、サロゲートペアとする必要のある補助文字は、
0x10000~0x10FFFFの範囲の文字で定義されているので、
符号 0x10000 を加算する。
0x10B9F + 0x10000 == 0x20B9F
[例]=================================================
叱 : Unicode値 : 0x20B9F
↓変換……したい。
叱 : UTF8で表現すると、0xF0 A0 AE 9F
(UTF8では、仕様上big endian も little endianも関係無い。)
====================================================
0x20B9Fは、0x00010000~0x001FFFFFの範囲にあるので、
UTF8の1バイト目は、1 1 1 1 0 □□□
UTF8の2バイト目は、1 0□□□□□□
UTF8の3バイト目は、1 0□□□□□□
UTF8の4バイト目は、1 0□□□□□□
0x20B9F == 0b 100000 101110 011111
を下の□から詰めていく。
UTF8の1バイト目は、1 1 1 1 0 □□□
UTF8の2バイト目は、1 0一零零零零零
UTF8の3バイト目は、1 0一零一一一零
UTF8の4バイト目は、1 0零一一一一一
↓残りの□を零で埋めます。
UTF8の1バイト目は、1 1 1 1 0 〇〇〇
UTF8の2バイト目は、1 0一零零零零零
UTF8の3バイト目は、1 0一零一一一零
UTF8の4バイト目は、1 0零一一一一一
↓整形
UTF8の1バイト目は、0b1111 0000 == 0xF0
UTF8の2バイト目は、0b1010 0000 == 0xA0
UTF8の3バイト目は、0b1010 1110 == 0xAE
UTF8の4バイト目は、0b1001 1111 == 0x9F
となります。
注意 : Bloggerで「𠮟 : 0x20B9F」を表示しようとするとバグるので、「叱 : 0x53F1」で代用。
このままメモ帳にコピペしてバイナリエディタで開くと、「0x53F1」の方なので注意。
詳細は前回を参照の事。
(wikiのUnicodeの方はちゃんと0x20B9Fで書いてあるのがあるので、それをコピペするか、バイナリエディタで直打ちしてメモ帳で開いて見ると良い。TeraPadとかを使うとバグる。(TeraPadの問題だが、新しいバージョンで改善されているかは不明。))
実験用テキストファイル(Stirling.exeなどのバイナリエディタで観察する。)
前回 次回
0 件のコメント:
コメントを投稿