2012-09-08 2 views
5

同じ内容の "你"(英語ではyou)の3つの異なる形式 - gbk \ utf-8 \ ucs-2のgeditと "ok1、ok2、ok3" "ないで、(またはUnicodeを言う)ユニコードエンディアンは私に戸惑う

>>> f1 = open('ok1', 'rb').read() 
>>> f2 = open('ok2', 'rb').read() 
>>> f3 = open('ok3', 'rb').read() 
>>> f1 
'\xc4\xe3\n' 
>>> f2 
'\xe4\xbd\xa0\n' 
>>> f3 
'`O\n\x00' 
>>> hex(ord("`")) 
'0x60' 
>>> hex(ord("O")) 
'0x4f' 

実際にはF3は、 '\ X60 \ x4f' ですが、次の出力は私だけUCS-2でエンディアンの問題がある理由

>>> '\xe4\xbd\xa0'.decode("utf-8") 
u'\u4f60' 
>>> '\xc4\xe3'.decode("gbk") 
u'\u4f60' 
>>> 

を混同しましたutf-8、gbkではなく?

答えて

5

UTF-8およびGBKは、バイトシーケンスでデータを格納します。これらのエンコーディングでどのバイト値が来るかが強く定義されています。このバイトオーダーは、コーディング、送信、またはデコードで使用されるアーキテクチャでは変更されません。一方

UCS-2又は2バイトのシーケンスにおける新しいUTF-16データを記憶します。これらの2バイトトークン内の個々のバイトの順序は、エンディアンのであり、基盤となるマシンアーキテクチャーによって異なります。システムでは、UCS-2にエンコードされたデータと通信する前に、トークンのエンディアンを識別する方法に関する合意が必要です。

ユニコードポイントU + 4F60は、UCS-2で2バイトの単一のトークン0x4F60としてコードされています。あなたのマシンはメモリアラインメントの中で最も重要なバイトの前に最下位バイトを置くので、シーケンス('0x60', '0x4F')がファイルに入れられます。したがって、ファイルの読み込みはこの順序でバイトを生成します。

それは2バイトのトークンを形成する前に、正しい順序でバイトを読み込みますので、Pythonはまだこのデータを正しくデコードすることができます。

>>> '`O\n\x00'.decode('utf-16') 
u'\u4f60\n' 
+0

メモリアラインメントの最下位バイトの前に最下位バイトを配置するため、シーケンス( '0x60'、 '0x4F')がファイルに格納されます。したがって、ファイルの読み込みでは、この順序でバイトが返されます。私のマシンでは、f1は '\ xe3 \ xc4 \ n'ではありませんか? f2はf2 '\ xbd \ xe4 \ xa0 \ n'ではありません –

+0

@Dd Pp:utf-8ファイルを書くとき、geditはバイト*を1つずつ*入れます。しかし、ucs-2コードファイルを書くとき、geditはバイトを2 * 2 *にします。バイト内の順序は、後者の場合のみエンディアンに依存します。 –

3

エンディアンネスは、マルチバイトの単語に適用されますが、UTF-8情報を符号化するために8ビットの単位を使用します(名前の8が表すものです)。そこに注文することの混乱の問題は決してありません。

場合によっては、情報をエンコードするために複数のユニットが必要な場合もありますが、区別されると考えられます。 Aという文字は、たとえば1バイト、0x41です。より多くのバイトを持つ文字をエンコードする必要がある場合は、先頭のインジケータバイトを使用し、続けて余分な継続バイトを使用して、その文字に必要なすべての情報を取得します。論理的には、これらは別個のユニットです。

GBKも同様の方式を使用します。文字は1バイトの単位を使用し、UTF-8と同様に、一部の文字に2番目のバイトを使用できます。

UCS-2(およびその後継者、UTF-16)は、2バイトのフォーマットです。情報を16ビット単位で符号化し、その16ビットは常に一緒になります。そのユニットの2バイトは論理的に一緒に属し、現代のアーキテクチャではこれらを1つの単位として扱い、格納されている順番を決定しています。これがエンディアンが入るところです。ユニットの2バイトの順序はアーキテクチャに依存します。 アーキテクチャーでは、バイトはリトルエンディアンを使用して順序付けられます。つまり、「より小さい」バイトが最初に送られます。これは、0x4Fバイトがファイル内の0x60バイトの前にある理由です。

pythonはビッグエンディアンかリトルエンディアンのいずれかを読み込めることに注意してください。何のインジケータ文字がスタート(バイトオーダーマーク、またはBOM)に存在しない場合は、明示的にエンディアンを選ぶことができます。

>>> '`O\n\x00'.decode('utf-16') 
u'\u4f60\n' 
>>> '`O\n\x00'.decode('utf-16-le') 
u'\u4f60\n' 
>>> 'O`\x00\n'.decode('utf-16-be') 
u'\u4f60\n' 

後者の例ではバイトが逆になっている、とビッグエンディアンとしてデコード。

関連する問題