要在 Python 2 和 Python 3 上获得一致的行为,您需要明确说明您的预期输出。如果你愿意,AAAAAAAAAAAAAAAAAAAAᆳ,那么\xde 就是垃圾;如果你想要AAAAAAAAAAAAAAAAAAAAï¾Þ,\xad 就是垃圾。无论哪种方式,打印您所拥有的内容的“解决方案”是显式使用 bytes 文字和 decode 以所需的编码,忽略错误。所以要获得AAAAAAAAAAAAAAAAAAAAᆳ(解释为UTF-8),你可以这样做:
print((b"A"*20+b"\xef\xbe\xad\xde").decode('utf-8', errors='ignore'))
如果要获得AAAAAAAAAAAAAAAAAAAAï¾Þ,你会这样做:
# cp1252 can be used instead of latin-1, depending on intent; they overlap in this case
print((b"A"*20+b"\xef\xbe\xad\xde").decode('latin-1', errors='ignore'))
重要的是,请注意文字前面的b;它们在 Python 2.7 上被识别和忽略(除非 from __future__ unicode_literals 生效,在这种情况下,就像在 Python 3 中一样需要它们)和在 Python 3 上,它使文字 bytes 文字(假定没有特殊编码) ,而不是 str 文字,因此您可以使用所需的编码进行解码。无论哪种方式,您最终都会得到原始字节,然后可以使用首选编码对其进行解码,而忽略错误。
请注意,忽略错误通常是错误的;你把数据丢在地上。 0xDEADBEEF 不能保证在任何给定的编码中产生有用的字节字符串,如果这不是你的真实数据,你可能仍然会因为想要默默地忽略不可解码的数据而冒着错误的风险。
如果您想写入原始字节并让任何消耗stdout 的内容随心所欲地解释它们,您需要低于print 级别,因为Python 3 上的print 纯粹基于str。要在 Python 3 上写入原始字节,您可以使用 sys.stdout.buffer(sys.stdout 是基于文本的,sys.stdout.buffer 是它包装的底层缓冲的面向字节的流);您还需要手动添加换行符(如果需要):
sys.stdout.buffer.write(b"A"*20+b"\xef\xbe\xad\xde\n")
对比在 Python 2 上,stdout 不是编码包装器:
sys.stdout.write(b"A"*20+b"\xef\xbe\xad\xde\n")
对于可移植代码,您可以提前获取“原始标准输出”并使用它:
# Put this at the top of your file so you don't have to constantly recheck/reacquire
# Gets sys.stdout.buffer if it exists, sys.stdout otherwise
bstdout = getattr(sys.stdout, 'buffer', sys.stdout)
# Works on both Py2 and Py3
bstdout.write(b"A"*20+b"\xef\xbe\xad\xde\n")