在python2中:
$ 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 Islam所说)
那么如何在python3中避免这种情况呢?
答案 0 :(得分:13)
考虑以下代码片段:
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 |................|
等等。没有惊喜;从0x80
到0xff
的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 |................|
总结:
0x80
到0xbf
的所有内容前置0xc2
。0xc0
到0xff
的所有内容都将第6位设置为零并且前缀为0xc3
。那么,这里发生了什么?
在Python 2中,字符串是ASCII,不进行转换。告诉它 写一些0-127 ASCII范围之外的东西,它说“okey-doke!”和 只写那些字节。简单。
在Python 3中,字符串是 Unicode 。当非ASCII字符是 写的,他们必须以某种方式编码。默认编码是 UTF-8。
那么,这些值如何用UTF-8编码?
从0x80
到0x7ff
的代码点编码如下:
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
这就是为什么你在c2
之前获得87
。
如何在Python 3中避免这一切?使用bytes
类型。
答案 1 :(得分:2)
Python 2的默认字符串类型是字节字符串。字节字符串写为"abc"
,而Unicode字符串写为u"abc"
。
Python 3的默认字符串类型是Unicode字符串。字节串写为b"abc"
,而Unicode字符串写为"abc"
(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'
打开文件并写入字节字符串。