2017-03-19 39 views
6

在python2:为什么python2和python3中的打印输出与相同的字符串不同?

$ python2 -c 'print "\x08\x04\x87\x18"' | hexdump -C 
00000000 08 04 87 18 0a         |.....| 
00000005 

在python3:

$ python3 -c 'print("\x08\x04\x87\x18")' | hexdump -C 
00000000 08 04 c2 87 18 0a         |......| 
00000006 

为什么出现在这里的字节"\xc2"

编辑

我觉得当字符串具有非ASCII字符,python3将字节"\xc2"追加到字符串。 (因为@Ashraful伊斯兰教说)

那么我怎么能在python3中避免这种情况?

+0

还有其他的例子吗?你能找到一个模式吗? –

回答

9

考虑下面的代码片段:

import sys 
for i in range(128, 256): 
    sys.stdout.write(chr(i)) 

运行这与Python 2,看看结果与hexdump -C

00000000 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f |................| 

等等。没有惊喜;从0x800xff的128个字节。

做同样使用Python 3:

00000000 c2 80 c2 81 c2 82 c2 83 c2 84 c2 85 c2 86 c2 87 |................| 
... 
00000070 c2 b8 c2 b9 c2 ba c2 bb c2 bc c2 bd c2 be c2 bf |................| 
00000080 c3 80 c3 81 c3 82 c3 83 c3 84 c3 85 c3 86 c3 87 |................| 
... 
000000f0 c3 b8 c3 b9 c3 ba c3 bb c3 bc c3 bd c3 be c3 bf |................| 

总结:

  • 一切从0x800xbf已经0xc2前缀。
  • 0xc00xff的所有内容都将第6位设置为零,并且前置0xc3

那么,这是怎么回事?

在Python 2中,字符串是ASCII码,没有转换完成。告诉 在0-127 ASCII范围之外写一些东西,它说“okey-doke!”和 只是写这些字节。简单。

在Python 3中,字符串是Unicode。当写入非ASCII字符 时,它们必须以某种方式编码为。默认编码是UTF-8,编号为 。

那么,这些值如何以UTF-8编码?

码点从0x800x7ff编码如下:

110vvvvv 10vvvvvv 

凡11个v字符是码点的比特。

这样:

0x80     hex 
1000 0000   8-bit binary 
000 1000 0000  11-bit binary 
00010 000000   divide into vvvvv vvvvvv 
11000010 10000000 resulting UTF-8 octets in binary 
0xc2 0x80   resulting UTF-8 octets in hex 

0xc0     hex 
1100 0000   8-bit binary 
000 1100 0000  11-bit binary 
00011 000000   divide into vvvvv vvvvvv 
11000011 10000000 resulting UTF-8 octets in binary 
0xc3 0x80   resulting UTF-8 octets in hex 

所以这就是为什么你87之前得到一个c2

如何在Python 3中避免这一切?使用bytes类型。

1

Python 2的默认字符串类型是字节字符串。字节字符串被​​写入​​,而Unicode字符串被写入u"abc"

Python 3的默认字符串类型是Unicode字符串。字节字符串被​​写为b"abc",而Unicode字符串被写入​​(u"abc"仍然有效)。由于有数百万个Unicode字符,因此将它们打印为字节需要进行编码(您的情况为UTF-8),这需要每个代码点有多个字节。

首先在Python 3中使用一个字节字符串来获得相同的Python 2类型。然后,因为Python 3的print期望Unicode字符串,请使用sys.stdout.buffer.write写入原始stdout接口,该接口需要字节字符串。

python3 -c 'import sys; sys.stdout.buffer.write(b"\x08\x04\x87\x18")' 

请注意,如果写入文件,也有类似的问题。对于无编码转换,以二进制模式'wb'打开文件并写入字节字符串。

相关问题