SlideShare uma empresa Scribd logo
1 de 53
Baixar para ler offline
文字コードってなんじゃらほい?


 とくにUnicodeってなによ?
文字コードの種類。



文字コード => なんかいっぱいある。

Shift-JIS とかEUC-JPとかUTF-8とか

UTF-16とかUTF-32とか・・・・・。

      あ!あとASCIIとか。
この本によると・・・・。
文字コードとは?

特定のユニークな文字(一文字分)と

 特定のユニークなバイナリ列との

    組み合わせらしい。

    つまりマーキング。
組み合わせ?

例えば、【A】という文字をパソコンちゃんが

ディスプレイに出力するには【A】という文字を

     知っている必要がある。

 でもパソコンちゃんは頭の痛い子なので

 【1】と【0】しか読めない・・・・・・。
しょうがないから【1】と【0】で。

 Aという文字と 1と0の組み合わせを
           
    紐付けるという作業をする。

    それが文字コード。たぶん。

Aは特定のユニークな1と0の並びに対応する。
確認してみる。



          value = A

p value .unpack( C* ) # => [65]

 ※unpack( C* )とは文字の値を
   0∼255の値にしてくれる。
  値は10進数で表記されるよ。
ん?
           

       [65]?
1と0の組み合わせじゃないじゃん?
人間用とパソコン用。

さっきの65は人間様が読みやすい用の

      10進数で書いてる奴。

 これをパソ用に2進数にしてやる。

p value . to_s(2) # => 1000001
これが組み合わせ。
   Aは  1000001  と組み合わせてある。

     つまりなんやかんやで人間が
 インターフェイスを通して 【1000001】という
     バイナリ列をパソコンに伝える。

       ・・・・・・・すると

パソコンは画面に【A】という文字を表示してくれる。
    人はこれをASCIIコードと呼ぶよね。
だけど、注意!
さっきは、一文字分をバイナリ列で表現するといった。

文字・・・【A】は文字だけど【1】は数字は?数値は?

パソコンにとっては文字だろうが数値・数字だろうが

          関係ない。

   同じく、数値もバイナリ列で表現される。
例えば?
                    value = 1
  value.to_s().encode("UTF-16BE").unpack( H*")
                    ⇒  ["0031"]

     数字の1・数値の1をバイナリ列にすると
        10進数で[ 49 ]となるよ♪

     さらに2進数にすると【 110001 】だよ。
【1】という値は確かに数値としてみると、2進数も16進数も
   【1】になるけど文字とバイナリ列の組み合わせを
       行うからここでは別問題なんだよね。
   言い換えれば【00000001】には既に他の文字が
        組み合わされているってわけ♪
んでもってこの沢山の組み合わせを?

   文字集合って呼んでいる。



Unicodeってやつももちろん文字集合。
Unicodeとはなんぞや?

 Unicodeっていうのはアメリカの人たちが

世界中の文字を【16ビット】つまり【2byte】で

     文字を組み合わせようぜ!!

     って言い出したのがキッカケ。
でも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】だよ。
ゲームボーイ版の・・・。


桃太郎伝説の最大所持金は



   65536両。
65536っていうことは
  【1】 と【0】の組合わせが65536通り分。

    文字と【1】 と【0】の組み合わせは

   絶対に重複(ちょうふく・じゅうふく)

         してはいけない。

 つまり65536通りの(しか)文字を表現できる。
      【00000000 00000000】
              ∼
      【11111111 11111111】

の組み合わせにそれぞれ文字が割り当てられるってこと。
たとえば?
       日本語の【あ】という文字。
   これを文字集合の対応する組み合わせだと
          確認してみる。

value = "あ".encode("UTF-16BE").unpack("H*")
                 ⇒  ["3042 ]

         パソコンが理解できるのは
        【 00110000 01000010 】
            の2進数表記だよ。
日本語の【あ】とは。

    Unicode文字集合上の

16bitで全部表すっていう仕様の上では

【3042】という2byteの組み合わせで

     表現されちゃうよ!
でも、登録すべき文字が

         予想より、多すぎた。

        当初のUnicodeの仕様上の

        16bitでの組み合わせじゃ

       足りなくなっちゃった・・・・。

(※いろんな国の人が文字を追加してくれって、言ってきたんだ
             ね。)
Unicodeの組み合わせの数は。

Unicodeは、16bitの固定長で文字とバイナリ列を
       組み合わせる(紐付ける)仕様。
               つまり、
        【00000000 00000000】
                ∼
        【11111111 11111111】
          までの組み合わせが
              考えられる。
これは16進数で【0x0000】∼【0xFFFF】となる。
でもね、実際は∼。


  65536通りの組み合わせすべてに
文字を割り当てていたわではなかったんだね。

          実は、

【D800】∼【DFFF】までは文字の割り当てが
      されていなかったらしいんだ。
  【D800】∼【DFFF】の組み合わせって
実は2048通りの【1】と【0】の組み合わせを
      作れることがわかったんだね。
偉い人たちは考えた。




 どうやって、これまで組み合わせきた他の文字と

バイト列をなくさないで文字とバイト列の組み合わせを

       増やそうかと・・・・。

2048通りの組み合わせがあっても、追加で増やしたい
     文字はぶっちゃけ半端無く多い・・・。

    2048文字程度の空きじゃ足りない。
偉い人達は開き直った。

           もうさ、

もう世界中の文字を16bitで表現するの・・・・・・

         諦めようぜ?

 追加分の文字はめんどくさいし桁増やそうぜ。
こうして、Unicodeの世界中の

    文字16bitでよくね?計画は、破綻した。

最終的に、これまで定義してきた根幹の16bit構想は

   維持しつつ、追加分に関しては桁を増やして

 5桁の、20bit(例えば 【0x20B9F】みたいな)
        で表そうということになった。
でも、20bitっていも【2^20】(2の20乗)分すべての
      組合わせをつかうわけじゃないよ。
ー符号化ー
    【0xD800】∼【0xDFFF】までの
       もともとのUnicode内に
ベンチ入りしてた組み合わせを、まず半分んこする。

    0xD800∼0xDBFF(1024通り)
               +
    0xDC00∼0xDFFF(1024通り)

 1024 1024=1048576通りの組み合わせを
            保持できるよ。
  あれ?これじゃさっきの5桁じゃなくね?
         8桁になっちゃうよ?
      【D800 DC00】みたいにさ?
     言ってること違うじゃないか!!
サロゲート。

   C#の無名関数みたいな奴はデリゲート。

       スネちゃまはデリケート。
    0xD800∼0xDBFF(1024通り)
                +
    0xDC00∼0xDFFF(1024通り)
      1024 1024=1048576通り

人はこれをサロゲートペアと呼んだ!!(千葉繁風に)
    0xD800∼0xDBFF(上位サロゲート)
                 +
    0xDC00∼0xDFFF(下位サロゲート)
ー8桁表記の文字を5桁表記へ。ー

    ーそれがUTF16。ー

パソコンが実際に理解するバイナリ列を

Unicodeとかで定義している文字集合と

組み合わせるために効率的に表記する。

  それが文字エンコーディング。

     文字符号化。諸々。
ー符号化といっても?ー

 当初Unicodeが定めていたいっちゃん最初の
  65536通りの文字はそのままなんだよ。
           てことは?

例えば【あ】これは【0x3042】で表記されるよ。

  でも、PC内でも同じように表記されるよ。

 "あ".encode("UTF-16BE").unpack("H*")
             => ["3042"]
         そう、Rubyならね♪
うん。だから【0x0000】∼【0xFFFF】までは
            楽なんだよね!
問題はね、追加分の文字だよね。

        例えば【 】という文字があるよ♪
    これはUnicodeの文字集合を見てみると【2000B】
    というコードポイントと組み合わせされているよ♪

                PC側ではどうなるの?
                    $value = " ";
$value = mb_convert_encoding($value,"UTF16","UTF8");
            $binary = unpack( H* ,$value);
                   print_r($binary);
            Array(  [1] => d840 dc0b )
                  そう!PHPならね♪
32bit表記を20bit表記へ

        8桁表記を5桁表記へ

   このサロゲートペアによる組み合わせを

        チョメチョメすることによって
       PC内部での表記【d840 dc0b】を
Unicode上の表記【0x2000B】にすることができる。

そう!エンコーディングで大変なのはここなんだ♪
PC上の符号化されたバイト列から

   文字集合のコードポイントに復元しちゃお!

           【d840 dc0b】の場合
        d840 => 上位サロゲート
        dc0b => 下位サロゲート
               になるね。
           さらに、上記の値から

0xd840 - 0xd800(上位サロゲートの先頭) = 0x40
 0xdc0b - 0xdc00(下位サロゲートの先頭) = 0xB
 0x40 * 1024 + 0xB + 0x10000 = 【0x2000B】

と、上記のような計算でUnicodeのサロゲート箇所の
  コードポイントを復元することができるよ。
では、UTF-16のまとめをするよ。
UTF-16の実態。その1


          UTF-16とは?

    Unicodeの文字集合を表現するための
        エンコーディング方法の一つ。

          当初、16bitだけで
表現させようとしていたコードポイントは、継続して
16bitで表現(※0x0000∼0xFFFFの組み合わせ)
   これをBMP【基盤他言語面 BMP】という。
UTF-16の実態。その2
  後に、16bitで対応できなくなってしまった際に
  追加した文字に対しては、コードポイント上では
5桁・・・つまり20bitで表現するという仕様に変更した。
   (※サロゲートペアによる組み合わせだね。)

   ただサロゲートペアの仕組みを実現するために
   ちょっとしたエンコーディングが必要になった。
上位2バイト - 0xd800(上位サロゲートの先頭) = ①
下位2バイト- 0xdc00(下位サロゲートの先頭) = ②
     ① 1024 + ② + 0x10000 = 符号位置
          この計算式のことだよ。
 ※RubyやPHPは特定の関数・メソッドでこの計算を
          やってくれてるんだね。
UTF-16の実態。その3
つまりUTF-16で任意の文字を表現しようとした場合、

      Unicode文字集合上では?=>

    0x0000 0xFFFFまでは16bitな文字。
          0xFFFFの値を超える
   コードポイントに関しては 20bitな文字。

          PCの内部では?=>

0x0000 0xFFFFまでは16bitな文字(2byte文字)
0xFFFFの値を超えるコードポイントに関しては
         32bitな文字(4byte文字)
           として認識される。
UTF-16の実態。その4


もっと掻い摘んでいうと。
=>
エンコーディング (符号化)とは

PC内部で文字を表記しているバイナリ列を

人間が定義した文字集合上のコードポイントに

復号させるための方法・定義など。たぶん。
では、次のページからUTF­8についてまとめてみるよ。
UTF-8とUTF-16の違いとは?その1


 ここまで、まとめたUnicodeの仕様を踏まえつつ

次はUTF-8のエンコーディングについてまとめてみる。

例えばUTF-16のエンコーディングにおいて【あ】は
    どのようなバイト列だったろうか?

       次の例を見てみてね♪
UTF-8とUTF-16の違いとは?その2


<?php
        $value = あ ;

        $value = mb_convert_encoding($value, UTF16 , UTF8 );

        print_r(unpack( H* ,$value));

        //以下出力結果だよ。

        [1]=>[3042]

        という値を取得することになる。
UTF-8とUTF-16の違いとは?その3


では次に、UTF-8における【あ】のバイト列はどのような値が
取得できるのだろうか?

<?php
        $value = あ ;
        $value = mb_convert_encoding($value, UTF8 , UTF8 );
        print_r(unpack( H* ,$value));
        //出力結果

        ["e38182"]

        ・・・・・・・・うーん? UTF-16の時とは似ても似つかない
        バイト列が返って来たね・・・。これはいったい?・・。
UTF-8とUTF-16の違いとは?その4

実はUTF-8って、UTF-16とは違って

PC内部側では、大部分の日本語は3byteで表記される。

[ e38182 ]=>よく見ると16進数記法で6桁ある・・・・・。

つまり、3byteで符号化(エンコーディング)されてるね!

逆にUTF-16の時は
[ 3042 ]=>だった。これはUnicodeの文字集合そのままの値だったね。
うん!
UTF-16は、BMP面の文字に対しては16bitで文字を割り当てる。

さらに、BMP面外(サロゲートペアによる組み合わせ)は
PC内部側では32bit(4byte)が割り当てられていたね。
UTF-16は【2byte】あるいは【4byte】じゃあ

 UTF-8は?いったい何byteでエンコードされているのか?

UTF-16のエンコーディング方式は比較的ラクだった。

けど、UTF-8はちょっと複雑だよ。

実は、UTF-8ってPC内部での表記が
【1byte】【3byte】【4byte】
と複数の割り当て方が存在しているんだよね・・・・。

まず、【1byte】で表記された場合これは256通りの文字割り当てが可
能ですが、ここにはASCIIコードとの互換保持のためASCIIコードがま
るごと定義されているのです。

だからA∼Zのアルファベットや0∼9までの数字なんかは
すべてASCIIと同じコードポイントが定義されているんだ。
UTF-8でエンコーディングした時の復号方法は?


じゃあ、UTF-8でのバイト列をどうやって
文字集合上のコードポイントに変換・復号するのだろうか。
例えば
#Rubyだよ。
#まず、単純に数値の場合。
testValue ="1";
p testValue . encode("UTF-8") . unpack( H*")
[31] => [31]

お!これはASCIIコードがそのまま出てきたね。
これは1byteだね。
UTF-8で日本語の扱いはどうなってるのか?
testValue = あ
testValue . encode("UTF-8").unpack("H*")
⇒  ["e38182"]

ん?16進数の6桁ということは3byteのバイト列で構成
されてるね。

でも実際の文字集合上の【あ】のコードポイントは
【3042】だね。
つまりこれからスクリプトが自動でUTF-8の符号化方法に
法ってUnicodeで定義されているコードポイントに直して
くれるわけだ。
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 定義の項目を参照のこと。
今の符号化を言語がすべてやってくれるのか・・。

  RubyとかPHPとか・・・あいつら意外にやるじゃん?

正直、RFCの計算方法はなんであんな方法なかのかは
わかりません。
とりあえず、あのような方法で復元できるということ。

そして・・・・。
RubyやPHPやPerlならunpackやpack
C#やJavaならEncoding系クラス及び
GetBytes系メソッドが今のをやってくれる。
次のページでUTF-8についてまとめるよ∼。
UTF-8の実態。その1


           UTF-8とは?

     Unicodeの文字集合を表現するための
         エンコーディング方法の一つ。
   でも、UTF-16の初期みたく固定長じゃないよ。
         可変長byteで符号化されてる。

   UTF-16とは異なり、ASCIIコードと互換性もつよ。
ASCIIと同じ7bit分の全く同じコードポイントをもってるよ。
UTF-8の実態。その2


       符号化した時、可変長。

UTF-16もBMPとサロゲートペア箇所はそれぞれ
      Byte数の異なる可変長だけどね。

    UTF-16とは異なり、UTF-8は
    【1byte】【2byte】【3byte】
    果ては、【4byte】とかもあるよ。
UTF-8の実態。その3




RFCでUTF-8の符号化・復号化の算出方法が定義されてる。

  符号化 1byteの時はそのままコードポイントになる。
2byte以降は、復号のためのちょっとした計算をしなくちゃ
              ならないよ。

  でも、そういうのは組み込み関数がやってくれる。
       Ruby => encodeメソッドとか
   PHP => mb_covert_encoding関数とかね。
まとめ。その1

    1.Unicode(文字集合)とは・・・。

 【文字】と【文字を紐付けるための符号位置】
を組み合わせたものをたくさん定義した表のこと。

 2.Unicodeと文字エンコーディングとは・・・。

 文字集合を元に、符号位置を再現するために
        バイナリ列を定義する仕様。
 「UTF-8」も「UTF-16」も「UTF-32」も
同じUnicodeという文字集合を別々のバイナリ列で
          表現するための方法。
まとめ。その2

     3. バイナリ列の復号・・・。

      各エンコーディングによって
文字集合上のコードポイントへバイナリ列を復号する
      復号方法がそれぞれ異なる。




          おわり。

Mais conteúdo relacionado

Destaque

文字コード勉強会
文字コード勉強会文字コード勉強会
文字コード勉強会典彦 平原
 
マイコンでマルチタスク
マイコンでマルチタスクマイコンでマルチタスク
マイコンでマルチタスクKatsuhiko Terawaki
 
オープン・ソースで構築するARMマイコン開発環境 ―― GCC,Eclipse,OpenOCDで統合開発環境,JTAGデバッグもできる!
オープン・ソースで構築するARMマイコン開発環境 ―― GCC,Eclipse,OpenOCDで統合開発環境,JTAGデバッグもできる!オープン・ソースで構築するARMマイコン開発環境 ―― GCC,Eclipse,OpenOCDで統合開発環境,JTAGデバッグもできる!
オープン・ソースで構築するARMマイコン開発環境 ―― GCC,Eclipse,OpenOCDで統合開発環境,JTAGデバッグもできる!Masaki Muranaka
 
文字コード入門 理論編 クイズ付き
文字コード入門 理論編 クイズ付き文字コード入門 理論編 クイズ付き
文字コード入門 理論編 クイズ付きTakao Baba
 
独学道場アセンブリの会
独学道場アセンブリの会独学道場アセンブリの会
独学道場アセンブリの会Ryota Suenaga
 
文字コードのお話
文字コードのお話文字コードのお話
文字コードのお話Shunji Konishi
 
Cコンパイラの改造(未)
Cコンパイラの改造(未)Cコンパイラの改造(未)
Cコンパイラの改造(未)7shi
 
文字コードに起因する脆弱性とその対策(増補版)
文字コードに起因する脆弱性とその対策(増補版)文字コードに起因する脆弱性とその対策(増補版)
文字コードに起因する脆弱性とその対策(増補版)Hiroshi Tokumaru
 
5分でインストール!awsでzabbix3.0
5分でインストール!awsでzabbix3.05分でインストール!awsでzabbix3.0
5分でインストール!awsでzabbix3.0Tadashi Mishima
 
create account book by c#
create account book by c#create account book by c#
create account book by c#Naoki Hanakawa
 

Destaque (20)

文字コード勉強会
文字コード勉強会文字コード勉強会
文字コード勉強会
 
マイコンでマルチタスク
マイコンでマルチタスクマイコンでマルチタスク
マイコンでマルチタスク
 
オープン・ソースで構築するARMマイコン開発環境 ―― GCC,Eclipse,OpenOCDで統合開発環境,JTAGデバッグもできる!
オープン・ソースで構築するARMマイコン開発環境 ―― GCC,Eclipse,OpenOCDで統合開発環境,JTAGデバッグもできる!オープン・ソースで構築するARMマイコン開発環境 ―― GCC,Eclipse,OpenOCDで統合開発環境,JTAGデバッグもできる!
オープン・ソースで構築するARMマイコン開発環境 ―― GCC,Eclipse,OpenOCDで統合開発環境,JTAGデバッグもできる!
 
文字コード入門 理論編 クイズ付き
文字コード入門 理論編 クイズ付き文字コード入門 理論編 クイズ付き
文字コード入門 理論編 クイズ付き
 
独学道場アセンブリの会
独学道場アセンブリの会独学道場アセンブリの会
独学道場アセンブリの会
 
文字コードのお話
文字コードのお話文字コードのお話
文字コードのお話
 
Cコンパイラの改造(未)
Cコンパイラの改造(未)Cコンパイラの改造(未)
Cコンパイラの改造(未)
 
文字コード基礎論A
文字コード基礎論A文字コード基礎論A
文字コード基礎論A
 
C#でゲームを作る2016 第1回
C#でゲームを作る2016 第1回C#でゲームを作る2016 第1回
C#でゲームを作る2016 第1回
 
Windows改造計画
Windows改造計画Windows改造計画
Windows改造計画
 
文字コードに起因する脆弱性とその対策(増補版)
文字コードに起因する脆弱性とその対策(増補版)文字コードに起因する脆弱性とその対策(増補版)
文字コードに起因する脆弱性とその対策(増補版)
 
C#でゲームを作る2016 第8回
C#でゲームを作る2016 第8回C#でゲームを作る2016 第8回
C#でゲームを作る2016 第8回
 
5分でインストール!awsでzabbix3.0
5分でインストール!awsでzabbix3.05分でインストール!awsでzabbix3.0
5分でインストール!awsでzabbix3.0
 
C++ マルチスレッド 入門
C++ マルチスレッド 入門C++ マルチスレッド 入門
C++ マルチスレッド 入門
 
hideya流 テストプレイ観察術
hideya流 テストプレイ観察術hideya流 テストプレイ観察術
hideya流 テストプレイ観察術
 
プログラムを高速化する話
プログラムを高速化する話プログラムを高速化する話
プログラムを高速化する話
 
よいコード、わるいコード
よいコード、わるいコードよいコード、わるいコード
よいコード、わるいコード
 
明日使えないすごいビット演算
明日使えないすごいビット演算明日使えないすごいビット演算
明日使えないすごいビット演算
 
create account book by c#
create account book by c#create account book by c#
create account book by c#
 
BCCとGCCの比較
BCCとGCCの比較BCCとGCCの比較
BCCとGCCの比較
 

Unicodeについて教えてgooでしつこくきいてみたよ♪