Unicodeについて教えてgooでしつこくきいてみたよ♪
- 7. 確認してみる。
value = A
p value .unpack( C* ) # => [65]
※unpack( C* )とは文字の値を
0∼255の値にしてくれる。
値は10進数で表記されるよ。
- 8. ん?
[65]?
1と0の組み合わせじゃないじゃん?
- 10. これが組み合わせ。
Aは 1000001 と組み合わせてある。
つまりなんやかんやで人間が
インターフェイスを通して 【1000001】という
バイナリ列をパソコンに伝える。
・・・・・・・すると
パソコンは画面に【A】という文字を表示してくれる。
人はこれをASCIIコードと呼ぶよね。
- 12. 例えば?
value = 1
value.to_s().encode("UTF-16BE").unpack( H*")
⇒ ["0031"]
数字の1・数値の1をバイナリ列にすると
10進数で[ 49 ]となるよ♪
さらに2進数にすると【 110001 】だよ。
【1】という値は確かに数値としてみると、2進数も16進数も
【1】になるけど文字とバイナリ列の組み合わせを
行うからここでは別問題なんだよね。
言い換えれば【00000001】には既に他の文字が
組み合わされているってわけ♪
- 15. でも16bitだと・・・・・。
16bitっていうのは2の16乗のこと。
つまり
2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2=2^16
答え 65536通り
0 65535までの数値を表現できる。
これを1と0だけで表現すると
65535 =【1111111111111111】だよ。
- 17. 65536っていうことは
【1】 と【0】の組合わせが65536通り分。
文字と【1】 と【0】の組み合わせは
絶対に重複(ちょうふく・じゅうふく)
してはいけない。
つまり65536通りの(しか)文字を表現できる。
【00000000 00000000】
∼
【11111111 11111111】
の組み合わせにそれぞれ文字が割り当てられるってこと。
- 18. たとえば?
日本語の【あ】という文字。
これを文字集合の対応する組み合わせだと
確認してみる。
value = "あ".encode("UTF-16BE").unpack("H*")
⇒ ["3042 ]
パソコンが理解できるのは
【 00110000 01000010 】
の2進数表記だよ。
- 19. 日本語の【あ】とは。
Unicode文字集合上の
16bitで全部表すっていう仕様の上では
【3042】という2byteの組み合わせで
表現されちゃうよ!
- 20. でも、登録すべき文字が
予想より、多すぎた。
当初のUnicodeの仕様上の
16bitでの組み合わせじゃ
足りなくなっちゃった・・・・。
(※いろんな国の人が文字を追加してくれって、言ってきたんだ
ね。)
- 24. 偉い人達は開き直った。
もうさ、
もう世界中の文字を16bitで表現するの・・・・・・
諦めようぜ?
追加分の文字はめんどくさいし桁増やそうぜ。
- 25. こうして、Unicodeの世界中の
文字16bitでよくね?計画は、破綻した。
最終的に、これまで定義してきた根幹の16bit構想は
維持しつつ、追加分に関しては桁を増やして
5桁の、20bit(例えば 【0x20B9F】みたいな)
で表そうということになった。
でも、20bitっていも【2^20】(2の20乗)分すべての
組合わせをつかうわけじゃないよ。
- 26. ー符号化ー
【0xD800】∼【0xDFFF】までの
もともとのUnicode内に
ベンチ入りしてた組み合わせを、まず半分んこする。
0xD800∼0xDBFF(1024通り)
+
0xDC00∼0xDFFF(1024通り)
1024 1024=1048576通りの組み合わせを
保持できるよ。
あれ?これじゃさっきの5桁じゃなくね?
8桁になっちゃうよ?
【D800 DC00】みたいにさ?
言ってること違うじゃないか!!
- 27. サロゲート。
C#の無名関数みたいな奴はデリゲート。
スネちゃまはデリケート。
0xD800∼0xDBFF(1024通り)
+
0xDC00∼0xDFFF(1024通り)
1024 1024=1048576通り
人はこれをサロゲートペアと呼んだ!!(千葉繁風に)
0xD800∼0xDBFF(上位サロゲート)
+
0xDC00∼0xDFFF(下位サロゲート)
- 28. ー8桁表記の文字を5桁表記へ。ー
ーそれがUTF16。ー
パソコンが実際に理解するバイナリ列を
Unicodeとかで定義している文字集合と
組み合わせるために効率的に表記する。
それが文字エンコーディング。
文字符号化。諸々。
- 29. ー符号化といっても?ー
当初Unicodeが定めていたいっちゃん最初の
65536通りの文字はそのままなんだよ。
てことは?
例えば【あ】これは【0x3042】で表記されるよ。
でも、PC内でも同じように表記されるよ。
"あ".encode("UTF-16BE").unpack("H*")
=> ["3042"]
そう、Rubyならね♪
うん。だから【0x0000】∼【0xFFFF】までは
楽なんだよね!
- 30. 問題はね、追加分の文字だよね。
例えば【 】という文字があるよ♪
これはUnicodeの文字集合を見てみると【2000B】
というコードポイントと組み合わせされているよ♪
PC側ではどうなるの?
$value = " ";
$value = mb_convert_encoding($value,"UTF16","UTF8");
$binary = unpack( H* ,$value);
print_r($binary);
Array( [1] => d840 dc0b )
そう!PHPならね♪
- 31. 32bit表記を20bit表記へ
8桁表記を5桁表記へ
このサロゲートペアによる組み合わせを
チョメチョメすることによって
PC内部での表記【d840 dc0b】を
Unicode上の表記【0x2000B】にすることができる。
そう!エンコーディングで大変なのはここなんだ♪
- 32. PC上の符号化されたバイト列から
文字集合のコードポイントに復元しちゃお!
【d840 dc0b】の場合
d840 => 上位サロゲート
dc0b => 下位サロゲート
になるね。
さらに、上記の値から
0xd840 - 0xd800(上位サロゲートの先頭) = 0x40
0xdc0b - 0xdc00(下位サロゲートの先頭) = 0xB
0x40 * 1024 + 0xB + 0x10000 = 【0x2000B】
と、上記のような計算でUnicodeのサロゲート箇所の
コードポイントを復元することができるよ。
- 34. UTF-16の実態。その1
UTF-16とは?
Unicodeの文字集合を表現するための
エンコーディング方法の一つ。
当初、16bitだけで
表現させようとしていたコードポイントは、継続して
16bitで表現(※0x0000∼0xFFFFの組み合わせ)
これをBMP【基盤他言語面 BMP】という。
- 35. UTF-16の実態。その2
後に、16bitで対応できなくなってしまった際に
追加した文字に対しては、コードポイント上では
5桁・・・つまり20bitで表現するという仕様に変更した。
(※サロゲートペアによる組み合わせだね。)
ただサロゲートペアの仕組みを実現するために
ちょっとしたエンコーディングが必要になった。
上位2バイト - 0xd800(上位サロゲートの先頭) = ①
下位2バイト- 0xdc00(下位サロゲートの先頭) = ②
① 1024 + ② + 0x10000 = 符号位置
この計算式のことだよ。
※RubyやPHPは特定の関数・メソッドでこの計算を
やってくれてるんだね。
- 36. UTF-16の実態。その3
つまりUTF-16で任意の文字を表現しようとした場合、
Unicode文字集合上では?=>
0x0000 0xFFFFまでは16bitな文字。
0xFFFFの値を超える
コードポイントに関しては 20bitな文字。
PCの内部では?=>
0x0000 0xFFFFまでは16bitな文字(2byte文字)
0xFFFFの値を超えるコードポイントに関しては
32bitな文字(4byte文字)
として認識される。
- 40. UTF-8とUTF-16の違いとは?その2
<?php
$value = あ ;
$value = mb_convert_encoding($value, UTF16 , UTF8 );
print_r(unpack( H* ,$value));
//以下出力結果だよ。
[1]=>[3042]
という値を取得することになる。
- 45. UTF-8で日本語の扱いはどうなってるのか?
testValue = あ
testValue . encode("UTF-8").unpack("H*")
⇒ ["e38182"]
ん?16進数の6桁ということは3byteのバイト列で構成
されてるね。
でも実際の文字集合上の【あ】のコードポイントは
【3042】だね。
つまりこれからスクリプトが自動でUTF-8の符号化方法に
法ってUnicodeで定義されているコードポイントに直して
くれるわけだ。
- 46. UTF-8で3byteで符号化されている文字を
Unicodeコードポイントに復元してみる。
①まず、[ e38182 ]という値を1byteずつ2進数に変換する。
E3 => 11100011
81 => 10000001
82 => 10000010
②上記で算出した2進数をRFCの定義に則って加工する。
11100011 => 0011(下位4bitを抜き取る)
10000001 => 000001(下位6bitを抜き取る)
10000010 => 000010(下位6bitを抜き取る)
③上記で抜粋したビット箇所をくっつける。
【00110000 01000010】
すると16bitのバイナリ列ができあがるのでこれを16進数に変換してみると?
【3042】というUnicode上の「あ」という文字のコードポイントを算出できる。
※UTF-8の符号化されたバイト列を、Unicodeのコードポイントに復元する方法は、それに明るサイトを参照。
http://lab.moyo.biz/translations/rfc/rfc2044-ja.xsp
上記サイトの、2. UTF-8 定義の項目を参照のこと。
- 49. UTF-8の実態。その1
UTF-8とは?
Unicodeの文字集合を表現するための
エンコーディング方法の一つ。
でも、UTF-16の初期みたく固定長じゃないよ。
可変長byteで符号化されてる。
UTF-16とは異なり、ASCIIコードと互換性もつよ。
ASCIIと同じ7bit分の全く同じコードポイントをもってるよ。
- 50. UTF-8の実態。その2
符号化した時、可変長。
UTF-16もBMPとサロゲートペア箇所はそれぞれ
Byte数の異なる可変長だけどね。
UTF-16とは異なり、UTF-8は
【1byte】【2byte】【3byte】
果ては、【4byte】とかもあるよ。
- 52. まとめ。その1
1.Unicode(文字集合)とは・・・。
【文字】と【文字を紐付けるための符号位置】
を組み合わせたものをたくさん定義した表のこと。
2.Unicodeと文字エンコーディングとは・・・。
文字集合を元に、符号位置を再現するために
バイナリ列を定義する仕様。
「UTF-8」も「UTF-16」も「UTF-32」も
同じUnicodeという文字集合を別々のバイナリ列で
表現するための方法。
- 53. まとめ。その2
3. バイナリ列の復号・・・。
各エンコーディングによって
文字集合上のコードポイントへバイナリ列を復号する
復号方法がそれぞれ異なる。
おわり。