• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:UTF-8とUTF-16について質問です。)

UTF-8とUTF-16についての質問

このQ&Aのポイント
  • UTF-8とUTF-16についての質問です。UTF-16でエンコーディングされたバイト配列を文字集合のコードポイントに復帰させることは可能ですか?また、UTF-8でエンコーディングされた文字列を文字集合のコードポイントに復帰させることは可能ですか?
  • UTF-8でエンコーディングされた文字列をバイト配列にした場合、元の文字集合に戻す方法はありますか?また、UTF-8とUTF-16が指す文字集合は同じものですか?
  • 以上の質問についてご教授いただけますか?

質問者が選んだベストアンサー

  • ベストアンサー
回答No.5

> つまりだいたいの日本語は > ユニコードのコードポイント値を10進数にすると0~65535までの数値でおさめている訳ですよね? 日本語,というよりも,Unicode制定当時の主要な文字コードで使われていた文字集合は,BMPに含まれます。 なので,日本語に限らず,ヨーロッパ各国語等 (ISO-8859ファミリ) や韓国語,中国語なども0~65535におさまっています。 > BMPというのはUnicodeの初期における定義ですよね。 はい。Unicodeの,であって,ISO/IEC 10646-1ではないです。 # ISO/IEC 10646は全く別ですし,ISO/IEC 10646-1は31bit系。 > ん?ていうことは、常に16bit(2バイト固定長?といういのでしょうか)で符号化された規格 > UTF-16というのは非常に使えない?(用途としては?)エンコード方式となるのですかね? 今のところ,内部エンコーディングとしてはUTF-16が一番効率がよいと思います。 後で書きますが,Unicode自体「1文字が複数コードポイントからなる」ことのある文字集合であり, その上でBMP外の文字が使われることが少なく,「1文字が複数コードポイントからなる」ことも少ないためです。 # 1文字に32bit使ってもクライアント側ならなんとかなるかもしれませんが……。 UTF-16は基本多言語面 (第0面) だけでなく,第16面までを16bit単位の符号化の中で使うための規格です。 そのために,BMPのU+D800 - U+DFFFは未定義領域になっています。 この領域の前半分,上位サロゲート (0xD800 - 0xDBFF) と後半分,下位サロゲート (0xDC00 - 0xDFFF) の2文字を組にすることによってBMP外の文字を使います。 これをサロゲートペアと呼びます。 UTF-16でのエンコードでは,上位サロゲートが先に,下位サロゲートが後にきます。 このサロゲートペアは,Unicodeのコードポイント「(上位サロゲート - 0xD800) * 1024 + (下位サロゲート - 0xDC00) + 0x10000」にマッピングされます。 なお,UTF-8は「コードポイントを符号化する」のであって,「UTF-16を別表現にする」のではないため,BMP外の文字は4バイトに直接符号化され,3バイト×2に符号化してはいけません。 また,そもそも「結合用文字」などがあるため,サロゲートペアを使わなくても1文字は固定長ではありません。 例えば,OS XのHFS+ではUnicode正規化D (NFD)であるため,「が」という文字は, ・WindowsではU+304C (が) が ・OS XではU+304B (か) U+3099 (結合用濁点) が となります。結合用文字はUnicode 1.0の頃から存在するため,元々「1文字」と「1コードポイント」は別物でした。 結合用文字はコードポイントが振られているので,UTF-8であっても結合用文字に独立した符号が割り当てられています (NFDで正規化した「が」は6バイト)。 > でもJAVAもC#も内部的?にはUTF-16だとかかいていたような・・。 はい。 なので,サロゲートペアや結合用文字を使うとlength/Lengthと文字数が一致しなくなります。 C#では,System.Globalization.TextInfoクラスなどを使って文字数や各文字情報を取得します。 http://msdn.microsoft.com/ja-jp/library/system.globalization.textinfo.aspx Javaでは,java.text.BreakIteratorクラスを使うそうです。 http://docs.oracle.com/javase/7/docs/api/java/text/BreakIterator.html > 文字列と文字列の比較の比較ってこの符号化したバイト列で判断しているんでしょうか? 通常は内部で保持している各文字の比較です。 文字の比較というのもややこしく,そのために先に出てきたUnicode正規化というものがあります。 XMLなどでは,「文書はUnicode正規化C (NFC) で書かれていること」が要求されていたりします。 # NFCでは正規分解後合成するため,結合用濁点付き平仮名は,対応する文字が定義されているならば単一のコードポイントになる > うーんでも 数値の1と文字列としての1だと矛盾するのか・・? これはPHPでの話でしょうか。 PHPの==による比較は,「数値」との比較は数値での比較になります。 1 == "1"は,1 == 1となります。 # 1 == "1a"も,1 == 1だったりしますが……。

1000vicki
質問者

補足

何度も何度もありがとうございます。 簡単にまとめると、 Unicodeという文字集合は あらゆる文字を 16ビットで表現しようとする規格で、当初はそれで問題なかった。 当初のUnicode規格はまさに16ビット分 256 ×256 =65536通りを表現していた。 (※これは基盤他言語面 BMPとなる箇所ですね) ただ後のサロゲートペアとなる部分は未定義だった。 その後、世界中の文字を文字集合に含める際に、65536通りの中に含めるには明らかに足りない。 そのときにとられた方法が > (0xD800 - 0xDBFF) と後半分,下位サロゲート (0xDC00 - 0xDFFF) の >2文字を組にすることによってBMP外の文字を使います。 >これをサロゲートペアと呼びます。 に当初運良く?未定義だった箇所を追加の文字集合として定義するのに使用したわけですね。 この際に、わざわざサロゲートペアを作った理由は 確認1. => 既に定義されていた BMP面の規格を崩すわけにはいかなかったからという捉え方でよいでしょうか? でこのサロゲートペアの符号化の方法ですが例えば ※てっとりばやかったのでPHPでやります。 <?php $value = "マルチバイト文字列"; $value ="𠀋"; print_r(unpack("C*",mb_convert_encoding("𠀋","UTF16","UTF8"))); と上記のようにサロゲートペア箇所に定義されている【𠀋】という文字をバイト列にした際の結果が以下 Array ( [1] => 216 [2] => 64 [3] => 220 [4] => 11 ) 16進数で表すと Array ( [1] => d840dc0b ) となりますよね。 でここで 最初の16ビット分【d840】が上位サロゲート部分 後の16ビット分【dc0b】が下位サロゲート部分 0xd840 - 0xd800 = 0x40 0xdc0b - 0xdc00 = 0xB 0x40 * 1024 + xB + 0x10000 = 0x2000B となりました。 Unicodeの文字集合で調べると【𠀋】という文字に一致しました。 (※この上記計算によって、第0面以外の面を参照するような形になるわけですね?) 確認2. => 上記のようにUnicodeは実質、各文字を16bitで表現(コードポイント)するというのは破綻しているわけですよね? >なお,UTF-8は「コードポイントを符号化する」のであって,「UTF-16を別表現にする」のではないため, >BMP外の文字は4バイトに直接符号化され,3バイト×2に符号化してはいけません。 これはなんというか、実際上記の【𠀋】という文字はUTF-8でも4byteで符号化されていますよね。 そのことですよね? あー、Unicodeってかなり仕様が深いですね。 とりあえずは、なんとなくつかめた感じす。

その他の回答 (4)

  • salsberry
  • ベストアンサー率69% (495/711)
回答No.4

> どのような法則でこのような計算になっているのか・・・・。 ANo.1に書かれている定義を見れば一目瞭然、比較的理解しやすい変換規則だと思うのですが、もしかして2進数とかビット演算にあまり馴染みがないのでしょうか。 UTF-8からUnicodeコードポイントへの変換: (1) 1バイト目を取ってくる (Xとする) (2) Xの最上位ビットが0ならば、Xを16ビットに拡張した値がUnicodeコードポイント → 終了 (3) Xの上位3ビットが110ならば (3a) 2バイト目を取ってくる (Yとする) (3b) Yの上位2ビットが10ならば、Xの下位5ビットとYの下位6ビットを合わせて16ビットに拡張した値がUnicodeコードポイント → 終了 (3c) Yの上位2ビットが10でないならばエラー → 終了 (4) Xの上位4ビットが1110ならば (4a) 2バイト目と3バイト目を取ってくる (YとZとする) (4b) YおよびZの上位2ビットが10ならば、Xの下位4ビットとYの下位6ビットとZの下位6ビットを合わせた値がUnicodeコードポイント → 終了 (4c) YまたはZの上位2ビットが10でないならばエラー → 終了 (5) Xの上位5ビットが11110ならば … 以下略 (6) Xの上位ビットが(2)~(5)の条件を満たさないならばエラー → 終了

1000vicki
質問者

お礼

あー、そういえば今まで考えていませんでしたが 文字列と文字列の比較の比較ってこの符号化したバイト列で判断しているんでしょうか? うーんでも 数値の1と文字列としての1だと矛盾するのか・・? そのときは型と型をみるのでしょうかね?

1000vicki
質問者

補足

おせわをかけます。 >ANo.1に書かれている定義を見れば一目瞭然、比較的理解しやすい変換規則だと思うのですが、もしかし >て2進数とかビット演算にあまり馴染みがないのでしょうか。 ええ。実はそうなのです。 コンピュータを専門で学んだことないので内部的挙動はかなり疎いです。 >(1) 1バイト目を取ってくる (Xとする) >(2) Xの最上位ビットが0ならば、Xを16ビットに拡張した値がUnicodeコードポイント → 終了 これは1バイト目 が 00000000 ~ 01111111 つまり1バイト目 が 0 ~ 127 まで これはたとえば特定の文字列(一文字分)を0~255の1バイトの範囲の数値に置き換えたとき (C#やJAVAならGetBytes()系メソッド?PHPやRubyならunpack系メソッドで行ったときに取得できる0~255間の 値のことですよね?) 0~127間の値であればアスキー文字だからその時点で終了。 どうも二進数になれていないのであれですが これってつまり特定の文字列(一文字分)から取得した最初の1バイト分の数値が 0~127だったら1バイト(0000 0000 ~0111 1111) 192~223までだったら2バイト文字(1100 0000 ~ 1101 1111) 224~239までだったら一般的な日本語の3バイト文字(1110 0000 ~ 11101111) 240~247までだったら日本語を扱う上ではあまりみかけない?4バイト文字(1111 0000 ~1111 0111) というようなとらえかたでよいのでしょうかね? これをみるに各バイト毎に256通り全てがわりあてられているわけではないのですね。 なんとなーくUTF-8がユニコード上のコードポイントをどのように符号化しているのか、 わかりました。 なるほどー・・・。 ありがとうございます、たすかりました。

回答No.3

#1補足1.は既に回答が付いたので……。 > つまりたいていの日本語はU+0800 - U+FFFFのコードポイントの範囲に収まっているということですかね。 JIS X 0208や0212の範囲のひらがな・カタカナ・漢字は全てその範囲に収まっています。 さらに,「機種依存文字」と呼ばれることのある,Windows-31jで追加された漢字もその範囲に含まれます。 JIS X 0213の文字の一部は基本多言語面 (BMP : U+0000 - U+FFFF) に含まれていないため,その一部の文字である「𠀋」などを使うと4バイトにエンコードされます。 > 上記解説部分は以下URLの >> http://lab.moyo.biz/translations/rfc/rfc2044-ja. … > 【2. UTF-8 定義】 > の項目の方法のことでしょうか? そうなります。 なお,RFC 2044はRFC 2279によって廃止され,さらにRFC 2279はRFC 3629によって廃止されています。 RFC 3629には4オクテットのシーケンスまでしか定義されていません。 RFC 2279には冗長形式によるセキュリティ問題が追加されました (冗長形式の例:. U+002EをC0 AEとエンコードする)。 http://tools.ietf.org/html/rfc2044 http://tools.ietf.org/html/rfc2279 http://tools.ietf.org/html/rfc3629

1000vicki
質問者

お礼

>JIS X 0208や0212の範囲のひらがな・カタカナ・漢字は全てその範囲に収まっています。 >さらに,「機種依存文字」と呼ばれることのある,Windows-31jで追加された漢字も >その範囲に含まれます。 つまりだいたいの日本語は ユニコードのコードポイント値を10進数にすると0~65535までの数値でおさめている訳ですよね? >JIS X 0213の文字の一部は基本多言語面 (BMP : U+0000 - U+FFFF) >に含まれていないため,その一部の文字である「𠀋」などを使うと4バイトに >エンコードされます。 PHPでunpackしてみると Array ( [1] => 240 [2] => 160 [3] => 128 [4] => 139 ) という値を取得できました 確かに4バイトで符号化されていますね。 BMPというのはUnicodeの初期における定義ですよね。 ん?ていうことは、常に16bit(2バイト固定長?といういのでしょうか)で符号化された規格 UTF-16というのは非常に使えない?(用途としては?)エンコード方式となるのですかね? でもJAVAもC#も内部的?にはUTF-16だとかかいていたような・・。

1000vicki
質問者

補足

なるほど・・・・。ユニコードの概要はなんとなーくつかめたような気がします。 がこのTUF-8の符号化の計算方法がまったくわかりませんね・・・。 これはもうこういう規則だと理解するしか無いんですかね? どのような法則でこのような計算になっているのか・・・・。

  • salsberry
  • ベストアンサー率69% (495/711)
回答No.2

> 1. 227 129 130 という並びは ユニコードの文字集合コードポイント値【0x3042】 > という値を指し示す・・・というか同義である > と解釈できるのでしょうか? 10進→2進で表すと 227→11100011 129→10000001 130→10000010 先頭バイトが1110で始まっているのでこれは3バイトで表された文字と判断できます。 各バイトから必要なビットを順に抜き出すと 0011 000001 000010 この16ビット2進数を16進数に直すと 0x3042 となります。

1000vicki
質問者

補足

ご解説ありがとうございます。 >先頭バイトが1110で始まっているのでこれは3バイトで表された文字と判断できます。 >各バイトから必要なビットを順に抜き出すと >0011 000001 000010 上記解説部分は以下URLの >http://lab.moyo.biz/translations/rfc/rfc2044-ja.xsp 【2. UTF-8 定義】 の項目の方法のことでしょうか?

回答No.1

えーっと,エンコーディングと文字集合は関係しませんよ。 例えば,Shift_JISで書かれたHTML 4.01の文書は, ・エンコーディング:Shift_JIS ・文字集合:ISO 10646-1 (≒Unicode) です。 さて,UTF-8とUnicodeコードポイントの変換ですが,定義があります。 ・U+0000 - U+007F (0000-0000 0abc-defg) そのまま1バイト値になる (0abc-defg) ・U+0080 - U+07FF (0000-0abc defg-hijk) 2バイトになる (110a-bcde 10fg-hijk) ・U+0800 - U+FFFF (abcd-efgh ijkl-mnop) ただしサロゲートペア部を除く 3バイトになる (1110-abcd 10ef-ghij 10kl-mnop) ・U+10000 - U+10FFFF (000a-bcde fghi-jklm nopq-rstu) 4バイトになる (1111-0abc 10de-fghi 10jk-lmno 10pq-rstu) 昔はこの先に5バイト,6バイトもありましたが現在は廃止されています。 ref) http://tools.ietf.org/html/rfc3629 http://ja.wikipedia.org/wiki/UTF-8

1000vicki
質問者

補足

いつも、ご教授ありがとうございます。 さて、解答いただいた内容が今ひとつ理解できないので ちょっと質問の仕方をかえて【あ】という文字のBytes配列 [0] => 227 [1] => 129 [2] => 130 つまり 1. 227 129 130 という並びは ユニコードの文字集合コードポイント値【0x3042】 という値を指し示す・・・というか同義である と解釈できるのでしょうか? また >・U+0800 - U+FFFF (abcd-efgh ijkl-mnop) ただしサロゲートペア部を除く >3バイトになる (1110-abcd 10ef-ghij 10kl-mnop) とありますね。 これはすなわち、 2. UTF-8で ひらがな漢字カタカタをバイト配列にすると 3バイト分を容量としてとりますよね? つまりたいていの日本語はU+0800 - U+FFFFのコードポイントの範囲に収まっているということですかね。 いまいち自分が、どのへんでつまずいているのもわかってないのですが・・・・。

関連するQ&A