- 締切済み
UTF-8とUTF-16およびUTF-32について
Unicodeにおける各文字エンコーディングについてですが なぜ、UTF-16およびUTF-32の文字コードがビッグエンディアンとリトル・エンディアンの二通りの組み合わせを許容できてUTF-8が許容できないのかがわかりませんなぜでしょうか?
- みんなの回答 (11)
- 専門家の回答
みんなの回答
- Tacosan
- ベストアンサー率23% (3656/15482)
本題とは関係ないけど, #10 の 「# ところで,wikiってどのWikiですか。」 ってのは wiki ≠ wikipedia ということだよ.
- Tacosan
- ベストアンサー率23% (3656/15482)
コードポイントが 16ビットで表せるなら (16ビット単位で扱う) UTF-16 でも同じ値を使うのが自然だし, わざわざ変える意味もない. まあ, 結局のところ「全世界の文字を 16ビットで表現する」という試みはやっぱり無謀だったわけだが... というか, それはいくらなんでもバカってもんだ.
- Yune-Kichi
- ベストアンサー率74% (465/626)
> 【あ】なら BEの場合 feff3042 となって > LEの場合 fffe4230というバイト列になります。 > なぜ この 30 と 42 という上位のバイト及び下位バイトとよばれる2つのbyteを > 前後入れ替えて表現しようとする仕様ができたのでしょうか? (略) > しているのだからわざわざリトル・エンディアンなんて仕様つくらなければよかったのにとおもったのですが・・・・ > この理由っていったいなんなのでしょうか? 根本的な間違いから。 「あ」のUTF-16BEやビッグエンディアン (BE) でのUTF-16におけるバイト列における表現は,30 42です。 UTF-16LEやリトルエンディアン (LE) でのUTF-16におけるバイト列における表現は,42 30です。 Byte Order Mark (U+FEFF) はUTF-16というエンコーディング(UTF-16BE/UTF-16LEではない)の場合に,BE/LEのどちらでバイト列に落としたのかを示すための印です。 BE,つまりは上位8ビットを前に書く場合,横にバイトの並びを書く上では自然ですし,わかりやすいです。 しかし,よくある「下位8ビットだけを使う」ような場合には,アドレス計算の処理が必要になります。 LE,つまりは下位8ビットを前に書く場合,横にバイトの並びを書く上では不自然に見えます。 しかし,よくある「下位8ビットだけを使う」ような場合に,アドレス計算をする必要がなくなります。 なので,コンピュータのアーキテクチャとして,ビッグエンディアンやリトルエンディアンが発生しました。 # 32ビットの下位16ビットだけを使う,もよくある話。大きな整数データ型から小さな整数データ型のキャストが全部このパターン。 で,このようなことがあるという「知識」の上でUTF-16が作られています。 # U+FEFFがZero Width No-Break Spaceであることを考えると,初期の段階で本当に考えられていたかは疑わしいところですが。 BEのコンピュータ上ではBEで情報交換するのが効率的ですし,LEのコンピュータ上ではLEで情報交換するのが効率的です。 片方に限ってしまうと,もう一方のアーキテクチャを持つコンピュータ上でUTF-16を利用して情報交換をするのが非常に非効率になります。 故に,両方をサポートすることが必要になります。 ちなみに,旧Macintoshで使われていたPowerPCやTCP/IPなどのネットワークの世界 (IPヘッダ等) はBE,PCや現行Macintoshで使われるIntelプロセッサではLEです。 また,ARMプロセッサは両用 (切り替え可能) です。 > 一つの表現というかそもそもUnicode上の符号位置がビックエンディアンで定義付け 符号位置にエンディアンはありません。符号位置は数値であって,バイト列に落としたものではないからです。 1バイトを越えるデータをバイト列にする場合に,初めてエンディアンが関係してくることを,ちゃんと認識していますか。 > 正直wikiにあるメモリ上のアドレス位置がどうのこうのいわれてもC言語の世界になっていてさっぱりわかりません・・・orz。 アドレスというのは,ノイマン型コンピュータの基礎知識です。 今あるコンピュータのほぼすべてはノイマン型です。 つまり,アドレスは今あるほぼすべてのコンピュータにおける基礎知識です。 # ところで,wikiってどのWikiですか。
- Yune-Kichi
- ベストアンサー率74% (465/626)
# この回答での前提条件:1バイト = 1オクテット = 8ビット > UTF-8なら2byteのときあるいあは3byteの時などありますが、 > 文字によって符号化時の上位・下位の有無が存在し(2byteの時は上位・下位存在するが、 > じゃあ3byteの時の上位・下位はどうやってきめるのか?決めようがないよね?という意?)整合性がないからというような捉え方ですかね? 整合性云々ではなく,そもそも存在しないのです。 まず,エンコーディングは「何ビット単位のデータか」ということが規定されます。 UTF-8であれば8ビット単位ですし,UTF-16であれば16ビット単位です。 UTF-8で3バイトになるというのは,8ビットのデータが3つ並ぶという意味であって,24ビット単位のデータを扱う,ということではありません。 次に,現実的なデータの取り扱い(メモリや通信等)は「1バイト = 8ビット単位」です。 便宜的に,以下ではこれを「データ取扱単位」と呼びます。 エンディアンは「エンコーディングでの単位データの並び方」を規定するのではなく,「現実的なデータの取り扱い上での8ビットを越えるデータの並び方」の規定です。 UTF-8は8ビット単位のデータを取り扱います。エンコーディングのデータサイズとデータの取り扱いサイズに違いがないため,エンディアンは発生しません。 UTF-16は16ビット単位のデータを取り扱います。なので,16ビット/8ビット=2データ取扱単位をどう並べるか,という2種類のエンディアンが発生します。 UTF-32は32ビット単位のデータを取り扱います。なので,32ビット/8ビット=4データ取扱単位をどう並べるか,という4!=24種類のエンディアンが発生します。現実的にはビッグ/リトルの2種類ですが。 CPUのエンディアンの話を書かれている方がいましたが,UTF-16/32と直接関わりません。 LEであるIntelプロセッサ上でUTF-16 BE/UTF-16 LEのどちらのデータも読み書きできます。 ただ,CPUにエンディアンがある原因は同じ理由で,「現実的なデータの取り扱い上での8ビットを越えるデータの並び方」をどう定めるか,という問題が発生するためです。
補足
>エンディアンは「エンコーディングでの単位データの並び方」を規定するのではなく, >「現実的なデータの取り扱い上での8ビットを越えるデータの並び方」の規定です。 うーんつまり、兎にも角にも,8bit単位で符号化されるUTF-8にはエンディアンが発生しようが ないということなのですね。 wikiからだと >エンディアン (英: endianness) とは、 >多バイトのデータ(即ち基本情報記憶単位を超えるデータ)を >メモリ上に配置する方式の種類のこと。 本回答の前の回答にも >さて,最初に書きましたがエンディアンは「2バイト以上の塊」を取り扱う場合の話です。 とありますね。 で、ひょっとすると今回の質問、エンディアン云々以前の問題かもしれませんが 、なぜマルチバイトのデータだと・・・・うーん伝え方が難しいのですが 【あ】なら BEの場合 feff3042 となって LEの場合 fffe4230というバイト列になります。 なぜ この 30 と 42 という上位のバイト及び下位バイトとよばれる2つのbyteを 前後入れ替えて表現しようとする仕様ができたのでしょうか? もう当初の質問とはそれてしまいますが・・・・。 もともと気になっていたのはこの部分かもしれません。 確かに UTF-16の2byteの場合において1byteごと前後入れ替えてもUnicode上の符号位置に復号しても前バイト列の先頭にfeffやfffeと負荷させておいてコンピューターが復元時にそれぞれの並び順の仕様にもとづいて矛盾は でてこないのでしょうけれど・・・一つの表現というかそもそもUnicode上の符号位置がビックエンディアンで定義付け しているのだからわざわざリトル・エンディアンなんて仕様つくらなければよかったのにとおもったのですが・・・・ この理由っていったいなんなのでしょうか? 正直wikiにあるメモリ上のアドレス位置がどうのこうのいわれてもC言語の世界になっていてさっぱりわかりません・・・orz。
- zwi
- ベストアンサー率56% (730/1282)
UTFの規格がハードウェア(CPU)の仕様に引きずられているのは確かですが、なるべく引きづらんれないのが一番です。UTF8はバイト単位で処理すれば良いので一番処理しやすい規格なのでないでしょうか。 >捉え方としてはBE型ハードウェアとLE型ハードウェアの2つがあって >それに対応するためにUTF-16およびUTF-32にはBOMが存在するというなかんじですかね? ややこしいことにBOMがないBE/LE決め打ちのUTF-16とかもあるんですけどね。まぁ規格なのでそういうものとして処理するしか無いんで実装をどうするかはプログラマが考えましょうって事です。私はコードを考えると可変長のUTF-8のLEやBEなんて処理したくないですが。
- wormhole
- ベストアンサー率28% (1626/5665)
>UTF-8なら2byteのときあるいあは3byteの時などありますが、文字によって符号化時の上位・下位の有無が存在し(2byteの時は上位・下位存在するが、じゃあ3byteの時の上位・下位はどうやってきめるのか?決めようがないよね?という意?)整合性がないからというような捉え方ですかね? 違います。 UTF-8(8ビット)は、バイト(8ビット)単位で扱おうとする以前にもうバイト(8ビット)単位になってるからです。
- zwi
- ベストアンサー率56% (730/1282)
エンディアンはCPUの設計の違いによるメモリから内部レジスタへの数値型の取込み方の違いです。つまり、リトル・エンディアン型CPUとビック・エンディアン型CPUが存在するのです。 UTF-8はバイト単位でとり込むので影響を受けませんが、UTF-16とUTF-32は数値型として2バイト、4バイト単位でCPUがとり込むのでCPUのエンディンの影響を受けます。違うエンディアン型のデータの場合はエンディアン変換を行わなくてはいけません。 こういう事情でデータ自体がエンディアンの種別を持っていないとうまく取り込むことが出来ないのでエンディアンと言う情報が必要なのです。
補足
ご回答ありがとうございます。 >エンディアンはCPUの設計の違いによるメモリから内部レジスタへの >数値型の取込み方の違いです。 >つまり、リトル・エンディアン型CPUとビック・エンディアン型CPUが >存在するのです。 これっていうのはつまり、 ハードウェア側にとある仕様があってそれは、リトル・エンディアン型CPUとビック・エンディアン型CPU があってこの仕様はUTF-16およびUTF-32の2つのエンコーディング方法にのみ該当しますよ。 ※ただし、この仕様はUTF-8には作用しませんよと。 本回答内容にその内部に取り込む際の詳細(PC内部の動き)が含まれていないのでここでは考えずに それぞれの仕様として上位のバイトから下位のバイトを取り込む BE型があり その逆の下位バイトから読み込み上位バイトをあとに読み込む LE型がある。 そして、その両CPUの両仕様に一つのファイルで対応できるように feff および fffeといBOMをバイト列先頭にくっつけると・・・・。 捉え方としてはBE型ハードウェアとLE型ハードウェアの2つがあって それに対応するためにUTF-16およびUTF-32にはBOMが存在するというなかんじですかね?
- wormhole
- ベストアンサー率28% (1626/5665)
>なぜ、UTF-16およびUTF-32の文字コードがビッグエンディアンとリトル・エンディアンの二通りの組み合わせを許容できてUTF-8が許容できないのかがわかりませんなぜでしょうか? 許容する意味がないから。 UTF-16(16ビット),UTF-32(32ビット)を1バイト(8ビット)単位で並べるとき UTF-16だと上位8ビット→下位8ビットの順(上位から下位)、下位8ビット→上位8ビットの順(下位から上位)があるわけですが、 UTF-8(8ビット)を1バイト単位で並べるとき元が8ビット単位なので上位も下位もありません。
補足
>UTF-16だと上位8ビット→下位8ビットの順(上位から下位)、 >下位8ビット→上位8ビットの順>(下位から上位)があるわけですが、 これは例えば UTF-16のAなら[0041]で上位が00 下位が41 対してUTF-8なら["41"] で1byteしかないから上位と下位がないということですか? UTF-8なら2byteのときあるいあは3byteの時などありますが、 文字によって符号化時の上位・下位の有無が存在し(2byteの時は上位・下位存在するが、 じゃあ3byteの時の上位・下位はどうやってきめるのか?決めようがないよね?という意?)整合性がないからというような捉え方ですかね?
- Yune-Kichi
- ベストアンサー率74% (465/626)
エンディアンというのは,2バイト以上の塊であるデータをバイト列にどの順序で並べるか,というものです。 http://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3%E3%83%87%E3%82%A3%E3%82%A2%E3%83%B3 0x01020304をビッグエンディアンで並べた場合は0x01 0x02 0x03 0x04の順に並べ, リトルエンディアンでは0x04 0x03 0x02 0x01の順に並べます。 その他にも,0x02 0x01 0x04 0x02や0x03 0x04 0x01 0x02のような特殊例もあるようです。 ref) http://www.w3.org/TR/xml/#sec-guessing-no-ext-info さて,最初に書きましたがエンディアンは「2バイト以上の塊」を取り扱う場合の話です。 UTF-8はオクテット (実質的にはバイト) の塊を並べる物です。 このため,UTF-8ではエンディアンが存在しないのです。
- fresh_homepie
- ベストアンサー率64% (24/37)
Unicodeで定義される文字集合は、あらゆる文字を U+0000 ~ U+10FFFF の文字コードに対応付けたもので、UTF-xxというのはその文字コードをコンピュータが利用するバイト列表現に変換する符号化方式のことを言います。 UTF-16はプログラム内部で扱いやすいように文字コードの整数値をそのまま16ビットデータとして表現したものです(U+0000~U+FFFFの範囲に限ればですが)。ただし、整数値の表現方法は処理系によってリトルエンディアン(LE)とビッグエンディアン(BE)の2通り存在するので、それに合わせてUTF-16でもLEとBEがともに定義されています。 一方、UTF-8は文字コードの整数値をそのまま使用するのではなく、1つのUnicode文字をある定められた規則に従って1~4バイトのバイトシーケンスに変換します。1つの決められた規則に従って変換するのですから、LEとかBEとかのような複数の表現方法が出てくる余地などありません。 例として挙げられた「あ」の場合を考えると、この文字は U+3042 に割り当てられています。16ビット整数表現(UTF-16)なら 0x3042 で、そのバイトシーケンスはLEなら「42 30」、BEなら「30 42」です。一方、UTF-8では提示された通り「E3 81 82」で、内部表現は文字コードを整数で表したものとは全く異なることが分かると思います。エンディアンを考えることに意味がないのは一目瞭然ですよね?
- 1
- 2
補足
>Byte Order Mark (U+FEFF) はUTF-16という >エンコーディング(UTF-16BE/UTF-16LEではない)の場合に, >BE/LEのどちらでバイト列に落としたのかを示すための印です。 となると http://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3%E3%83%87%E3%82%A3%E3%82%A2%E3%83%B3 上記wikiにもあるように >>BOMがない場合には、ビッグエンディアンだと決められている(→ UTF-16)。 通常のUTF-16にはBEで復元されるが、通常のUTF-16の場合BOMをつけてやるのが良いんですね。 UTF-16BEやUTF-16LEと保存時に、指定されている場合はBOMをつけなくても可と。 どうやらBOM付きのUTF-16BEやUTF-16LEもあるようですが。 確かにエディタなどにはBOM付きBEとLEやBOMなしのBEやLEを指定できるようになってますね。 てことは UTF-16のエンコード時の仕様としては UTF-16(BOMあり) => feffかfffeがバイト先頭に存在するので復号時の判断が可能と。 UTF-16(BOMなし) => ただし復号時はかならずBEで復元される、この場合LEで保存された場合文字化けしますよね? UTF-16BE(BOMあり)=>この場合は復号時のエンディアンをBEと決定しているのでBOMは無視されるのか?ためしたほうがはやいですね・・。 UTF-16BE(BOMなし)=>この場合はBEで復号することを最初から決定している UTF-16LE(BOMあり)=>この場合はLEで復号することを最初から決定している UTF-16LE(BOMなし =>この場合はLEで復号することを最初から決定している >故に,両方をサポートすることが必要になります。 とあるように 普通にあつかうならBOM付きUTF-16が一番トラブルがないのでしょうね。 >で,このようなことがあるという「知識」の上でUTF-16が作られています。 つまりBEやLEなどのエンディアンが存在するのは、ハードウェア側の都合っていうことですか?・・。 >符号位置にエンディアンはありません。符号位置は数値であって, >バイト列に落としたものではないからです。 あくまで符号位置(コードポイント)は、 文字集合上で文字が何番目に配置されているかの順番ってことですね。 UTF-16で符号位置がそのまま符号化されたときと同じ値になるのは2byteで符号化するための都合よく 同じ値になっていると?(見た目上でですね) ※このへんのキーワードがちょっとあいまいですね・・・。 うまいことまとめた文献などがあるとよいのですが・・・。 >符号位置にエンディアンはありません。符号位置は数値であって, >バイト列に落としたものではないからです。 >1バイトを越えるデータをバイト列にする場合に, >初めてエンディアンが関係してくることを,ちゃんと認識していますか。 ここは、符号位置の見た目がUTF-16で符号化した際のビックエンディアンと同じ見た目なのに なんでわざわざその逆の符号化をする仕様が存在するのかなという意ですね。 # ところで,wikiってどのWikiですか http://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3%E3%83%87%E3%82%A3%E3%82%A2%E3%83%B3 上記ウィキの中腹以降です。Cのコードでの説明は一番最下部あたりにでてきますが。