对于 Python 3(3.8 和之前的版本回到 3.6),
surrogatepass
是默认的错误处理程序。
对于文件路径与此编码不匹配的用户来说,这可能会导致问题。
为什么 Windows 使用 surrogatepass
surrogateescape
,后者可以处理这些字节。例如:
>>> import sys
>>> sys.getfilesystemencoding(), sys.getfilesystemencodeerrors()
('utf-8', 'surrogateescape')
>>>
>>> # This raises an error:
>>>
>>> b'C:\\Users\\me\\OneDrive\\\xe0\xcd\xa1\xca\xd2\xc3\\my.txt'.decode('utf-8', errors="surrogatepass")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe0 in position 24: invalid continuation byte
>>> # Compared to:
>>> b'C:\\Users\\me\\OneDrive\\\xe0\xcd\xa1\xca\xd2\xc3\\my.txt'.decode('utf-8', errors="surrogateescape")
'C:\\Users\\me\\OneDrive\\\udce0͡\udcca\udcd2\udcc3\\my.txt'
注意,我猜测这可能是必要的,因为底层 NTFS 文件系统使用 UTF-16 而不是空终止字节,需要对 Linux/macOS 上不存在的 Python 文件系统编码进行一些限制。根本原因是Windows和*nix采用完全不同的方式来采用unicode。
同样,当 MS 为 FAT(在实现它的驱动程序之后称为“vfat”)和 ISO9660(称为 Joliet)开发“长文件名”扩展时,这些扩展都是基于 16 位 Unicode 的。
然而 16 位 Unicode 时代并没有持续太久。特别是来自中国的强大压力,要求不仅对当前汉字进行编码,还要对历史汉字进行编码。同样,软件供应商也不想再次迁移文本格式。结果就是 UTF-16,一种使用 16 位代码单元的可变宽度编码,是原始 16 位编码的扩展。
与此同时,类 Unix 系统仍然坚持使用 8 位字节作为其基本文本单位。 UTF-8 被视为另一种面向字节的扩展 ASCII 编码,随着时间的推移,它逐渐取代了其他扩展 ASCII 编码。
在这两种情况下,程序都可能从操作系统接收在假定编码中无效的字符串。此外,在某些情况下,特别是涉及文件名的情况下,有必要处理这些字符串并将它们以无损的方式传递回操作系统。
这就是为什么 python 3 中添加了“surrogatepass”和“surrogateescape”编码选项的原因。
“surrogateescape”是为扩展 ascii 编码而设计的。当与这种编码一起使用时,它允许将任何字节序列转换为 python 字符串,并将生成的 python 字符串转换回字节序列,而不会丢失任何信息。 Python 允许您使用 UTF-16 指定“surrogateescape”,但它似乎实际上并不能正常工作,而且没有意义。
“surrogatepass”专为与 UTF-16 一起使用而设计。与 UTF-16 一起使用时,它允许将任何 16 位单元序列转换为 python 字符串,然后再转换回原始 16 位单元序列。它可以与其他 Unicode 编码一起使用,并且在某些情况下这样做可能有意义,但有大量无效的 UTF-8 序列在指定“surrogatepass”时仍然无效。