2017-08-09 8 views
2

これをPythonで文字列の長さをバイト数で取得しようとしました。python3.5の文字列の長さと異なるエンコード

>>> s = 'a' 
>>> s.encode('utf-8') 
b'a' 
>>> s.encode('utf-16') 
b'\xff\xfea\x00' 
>>> s.encode('utf-32') 
b'\xff\xfe\x00\x00a\x00\x00\x00' 
>>> len(s.encode('utf-8')) 
1 
>>> len(s.encode('utf-16')) 
4 
>>> len(s.encode('utf-32')) 
8 

UTF-8英語の文字を格納するために使用1つのバイトが、なぜUTF-16使用の4つのバイト? len()は正確に何を測定していますか?

答えて

2

UTF-16は可変長エンコードです。コードポイントは、1つまたは2つの16ビットコードユニット(すなわち、2または4バイト、および 'a'は2バイト)で符号化される。

UTF-32は固定幅であり、コードポイントあたり正確に32ビット(つまり4バイト)です。

あなたが見ている長さは、そのようなlenをnaically使ったときにBOM(\ xff \ xfeものがBOM)を含むため、膨らんでいるようです。

>>> 'a'.encode('utf-16') 
b'\xff\xfea\x00' 
    BOM.....a.... 
>>> 'aaa'.encode('utf-16') 
b'\xff\xfea\x00a\x00a\x00' 
    BOM.....a....a....a.... 

あなたがbitstringモジュールを使用して、生のビットを見ればそれはあなたのための明確であるかもしれない:

>>> # pip install bitstring 
>>> from bitstring import Bits 
>>> Bits(bytes='a'.encode('utf-32')).bin 
'1111111111111110000000000000000001100001000000000000000000000000' 
>>> Bits(bytes='aaa'.encode('utf-32')).bin 
'11111111111111100000000000000000011000010000000000000000000000000110000100000000000000000000000001100001000000000000000000000000' 
BOM.............................a...............................a...............................a............................... 

UTF-8を再び可変幅で、1-4の8ビット・ブロックを使用して、最初の128文字のASCIIにマッチします。これには 'a'が含まれます。ユニコード標準では、BOMがUTF-8で許可されていますが、その使用は必須でも推奨もしていません(意味がありません)。これは最初の例でBOMが表示されない理由です。

0

あなたの長さが奇妙に見える理由は、UTF-16およびUTF-32エンコーディングがエンコーディング中に文字列の先頭にbyte order markを追加しているためです。だからこそ、文字列の長さは、あなたが期待する文字列の2倍に見えます。彼らは2つのコードポイントを使用しています。バイトオーダーマークは、いくつかのことを示します(エンディアンとエンコーディングが主なものです)。したがって、基本的にlenは期待通りに機能しています(エンコードされた表現で使用されるバイト数を測定しています)。

0

len()オブジェクトの長さ(アイテム数)を返します。文字列をエンコードするときs.encode('utf-16') pythonは、バイトオーダー記号の文字列のエンコードされたバージョンを返します。それは文字列の長さに数えられます。私のポイントを説明するために

for i in range(0, len(s.encode('utf-16'))): 
    print(s.encode('utf-16')[:i]) 

結果:

b'' #this is the byte order mark 
b'\xff' 
b'\xff\xfe' 
b'\xff\xfea' 
関連する問題