2015年2月17日火曜日

Unicode処理①::Unicode値をUTF16(エスケープしたサロゲートペア)へ変換(分解)する。

ちょっと頭が弱くて、
サロゲートペア入門
の記事がすぐに理解できなかったのでメモ。

参考資料:文字コードに関する覚え書きと実験

webでサロゲートペアに対応しているエンコーダ&デコーダ
:Unicodeエスケープシーケンス変換ツール


[例]==========================================



 ( Unicode値 : 0x20B9F ) ← UTF16で、エスケープするとサロゲートペアになる文字。



↓エスケープ・シーケンスに変換    ↑デーコード

                 \ud842\udf9f

=============================================(サロゲートペア入門のページの例より)

処理としては以下の手順になります。



注  ::  0x:16進数 , 0d:10進数 , 0b:2進数


0x20B9F == 0b0010  0000  1011  1001  1111


ここで、

補助文字(1面~16面:U+10000 ~ U+10FFFF)
」(参考ページより引用)
つまり、0x10000~0x10FFFFの範囲の文字は、補助文字として扱われる。
となっているので、この符号を消したい。
(データを減らすため??……いや、たぶん符号データは単なる目印なので、一度取り除いておきたい??)

従って、0x10000を引き算する

0x20B9F - 0x10000
  ==  0x10B9F
  ==  0b0001  0000  1011  1001  1111

↓前半分と後ろ半分に分割する。

   前半分:  0b0001  0000  10
後ろ半分:  0b11  1001  1111

↓整形

   前半分:  0b□□00  0100 0010  ==  0x042
後ろ半分:  0b□□11  1001  1111  ==  0x39F

まず、これを上半分と後ろ半分に切り分けます。
始めに張ったリンク先ではこの処理を0x400で割った時の商と剰余を用いて求めています。
当然ビットシフトで実装しても全く問題ありません。

一応、何故0x400で割るのかを説明しておくと、
    0x400 == 0b0000  0000  0100  0000  0000
と、丁度半分の桁となる為です。


ところで、

上位サロゲート符号単位 (high (or leading) surrogate code unit):U+D800 ~ U+DBFF (1024 code points)
下位サロゲート符号単位 (low (or trailing) surrogate code unit):U+DC00 ~ U+DFFF (1024 code points) 
」(参考ページより引用)
つまり、
0xD800~0xDBFFの範囲の文字(0b1101  10XX  XXXX  XXXX  (X : 任意))は上位サロゲートの文字で、
0xDC00~0xDFFFの範囲の文字(0b1101  11XX  XXXX  XXXX  (X : 任意))は下位サロゲートの文字である事を意味しています。

となっているので、
前半分に0xD800,後ろ半分に0xDC00を加算します。
つまり、

   前半分:  0x042  +  0xD800  ==  0xD842
後ろ半分:  0x39F  +  0xDC00  ==  0xDF9F


従って、答えは、

上位サロゲートが0xD842
下位サロゲートが0xDF9F

を、エスケープシーケンスで書き直して、

\uD842
\uDF9F

となります。

=============================================
ところで、
「叱」をテキストでUTF16を指定して保存し、バイナリエディタで開くと、
0x53F1として保存されているので、「あれっ?」と思ったのですが、
       big endian : 0x53 F1
    little endian : 0xF1 53
(普通に変換したら0x53F1の方に変換されただけで、0x20B9Fが使えない訳では無い。)
wikiのUnicode曰く、

常用漢字の2010年改定で追加された字のうち「𠮟」はU+20B9Fで追加漢字面に含まれる。そのため、改定後の常用漢字完全サポートを謳う場合、Unicodeに対応していて更にこの拡張領域にも対応している必要があると言える。ただ、現状ではこの字はJIS X 0208にも含まれていて、基本多言語面に含まれる異体字の「叱」(U+53F1) で代用されることが多い。
」(wikiのUnicodeより引用)

だそうで、非常に困った扱いですが、仕方ないがですね……。

バイナリで保存する時、バイナリの値は、「𠮟」の場合、
       big endian : 0xD8 42 , 0xDF 9F
    little endian : 0x42 D8 , 0x9F DF
となります。

UTF16の    big endian (UTF16BE) の場合、テキストファイルの先頭に、0xFE , 0xFF
UTF16の little endian (UTF16LE) の場合、テキストファイルの先頭に、0xFF , 0xFE
(BOM::BitOrderMarkと呼ばれている)が付けられ、これを元に、テキストファイルなどは、
指定された文字コードでファイルを開くことができる。
(無いと自動判定でもできなければ、おそらく文字化けする。)

ちなみに、IEでもChromeでも、wikiをそのままコピペした結果、
上記の引用の内「U+20B9F」の方がバグっていますが、原因は良く分からないです……。
(Bloggerの編集画面では正常だし、wikiで見る分には正常なのですが……。Bloggerの問題??)
→いやいや、Bloggerの内部の文字コードと一致していないのかな。(結局良く分からないですが、UTF16じゃないのかな??、と。)

次回

0 件のコメント:

コメントを投稿