如果您不知道编码,那么要以 Python 3 和 Python 2 兼容的方式将二进制输入读入字符串,请使用古老的 MS-DOS CP437编码:
PY3K = sys.version_info >= (3, 0)
lines = []
for line in stream:
if not PY3K:
lines.append(line)
else:
lines.append(line.decode('cp437'))
因为编码是未知的,所以期望非英文符号翻译成cp437
(英文字符不被翻译,因为它们在大多数单字节编码和 UTF-8 中匹配)。
将任意二进制输入解码为 UTF-8 是不安全的,因为您可能会得到以下信息:
>>> b'\x00\x01\xffsd'.decode('utf-8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 2: invalid
start byte
这同样适用于latin-1
Python 2 的流行(默认?)。查看代码页布局中的缺失点- 这是 Python 与臭名昭著ordinal not in range
的 .
更新 20150604:有传言称 Python 3 具有将surrogateescape
内容编码为二进制数据而不会丢失数据和崩溃的错误策略,但它需要转换测试[binary] -> [str] -> [binary]
,以验证性能和可靠性。
更新 20170116:感谢 Nearoo 的评论 - 也有可能使用backslashreplace
错误处理程序对所有未知字节进行斜线转义。这仅适用于 Python 3,因此即使使用此解决方法,您仍然会从不同的 Python 版本中获得不一致的输出:
PY3K = sys.version_info >= (3, 0)
lines = []
for line in stream:
if not PY3K:
lines.append(line)
else:
lines.append(line.decode('utf-8', 'backslashreplace'))
有关详细信息,请参阅Python 的 Unicode 支持。
更新 20170119:我决定实现适用于 Python 2 和 Python 3 的斜线转义解码。它应该比cp437
解决方案慢,但它应该在每个 Python 版本上产生相同的结果。
# --- preparation
import codecs
def slashescape(err):
""" codecs error handler. err is UnicodeDecode instance. return
a tuple with a replacement for the unencodable part of the input
and a position where encoding should continue"""
#print err, dir(err), err.start, err.end, err.object[:err.start]
thebyte = err.object[err.start:err.end]
repl = u'\\x'+hex(ord(thebyte))[2:]
return (repl, err.end)
codecs.register_error('slashescape', slashescape)
# --- processing
stream = [b'\x80abc']
lines = []
for line in stream:
lines.append(line.decode('utf-8', 'slashescape'))