"surrogateescape"无法逃避某些角色

dot*_*hen 7 python unicode encoding utf-8

关于在Python中读写文本文件,其中一个主要的Python贡献者提到了有关surrogateescapeUnicode错误处理程序的问题:

[surrogateescape]通过在Unicode代码点空间的一个小部分使用的数据中处理数据来处理解码错误.编码时,它会将那些隐藏的值转换回无法正确解码的确切原始字节序列.

但是,在打开文件然后尝试将输出写入另一个文件时:

input_file = open('someFile.txt', 'r', encoding="ascii", errors="surrogateescape")
output_file = open('anotherFile.txt', 'w')

for line in input_file:
    output_file.write(line)
Run Code Online (Sandbox Code Playgroud)

结果是:

  File "./break-50000.py", line 37, in main
    output_file.write(line)
UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc3' in position 3: surrogates not allowed
Run Code Online (Sandbox Code Playgroud)

请注意,输入文件不是 ASCII.但是,它会在包含非ASCII字符的数百行之前横切它,然后才会在一个特定行上抛出异常.输出文件必须是ASCII并且丢失一些字符就好了.

这是在解码为UTF-8时抛出错误的行:

'Zoë的咖啡馆'

这是十六进制编码:

$ cat z.txt | hd
00000000  27 5a 6f c3 ab 5c 27 73  20 43 6f 66 66 65 65 20  |'Zo..\'s Coffee |
00000010  48 6f 75 73 65 27 0a                              |House'.|
00000017
Run Code Online (Sandbox Code Playgroud)

为什么surrogateescapeUnicode Error Handler会返回 ASCII字符?这是在Kubuntu Linux 12.10上的Python 3.2.3.

Ign*_*ams 9

为什么surrogateescape Unicode Error Handler会返回不是ASCII的字符?

因为这就是明确的做法.这样你可以用另一种方式使用相同的错误处理程序,它将知道该怎么做.

3>> b"'Zo\xc3\xab\\'s'".decode('ascii', errors='surrogateescape')
"'Zo\udcc3\udcab\\'s'"
3>> "'Zo\udcc3\udcab\\'s'".encode('ascii', errors='surrogateescape')
b"'Zo\xc3\xab\\'s'"
Run Code Online (Sandbox Code Playgroud)


小智 6

单独的代理不应该用 UTF-8 编码——这正是它被用于无效输入的内部表示的原因。

在现实生活中,得到的数据对于它“应该”采用的编码无效是很常见的。例如,这个问题的灵感来自于看起来是 Latin-1 的文本,当 ASCII 或 UTF-8预料之中。我将“假设”放在引号中,因为“编码信息”只是一个猜测,可能与实际文件无关,这是很常见的。

默认情况下,xml 处理(和大多数 unicode 处理)是严格的——即使它可以很好地处理数百个其他行,整个过程也会放弃。

使用 errors=replace 解码会将该行变成“Zo?'s Coffee House”,这是一个改进。(好吧,除非您尝试用其他无效字符替换无效字符——并且官方的 unicode 替换字符在 ASCII 中无效,这就是为什么通常使用 '?' 进行编码的原因。)

surrogateescape 当程序员决定“你知道吗?我不在乎数据是否垃圾。也许有错误的编解码器......所以我将按原样传递未知字节。” Python 确实必须在内部存储(但避免解释)这些字节,直到它们被传递。

使用不成对的代理允许 Python 存储无效字节而无需额外转义。正是因为未配对的代理是无效的,所以它们永远不会出现在有效的输入中。(如果它们无论如何发生,它们将被解释为一对无法识别的字节,这两个字节都被保留以供输出。)

原始发布者的问题是他试图直接打印出内部表示,而不是首先反转映射,并且内部表示具有(故意)无效的字节......因此默认(严格)错误处理程序拒绝.