2014-01-14 52 views
4

关于在Python阅读和写作的文本文件,one of the main Python contributors mentions这对于surrogateescape Unicode的错误处理程序:“surrogateescape”无法逃避某些字符

[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) 

结果:

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 

注意,输入文件 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 

为什么surrogateescape Unicode错误处理程序返回的字符是而不是 ASCII码?这是在Kubuntu Linux 12.10上的Python 3.2.3。

+0

你是否在你的python文件的头文件中指定了编码?只是一个快速检查。 –

+3

@DylanLawrence:这与代码处理的数据完全无关。 –

+0

@DylanLawrence:1)这是Python 3,所以没有必要。 2)这与读取数据有关,而不是Python文件本身的编码。 – dotancohen

回答

6

为什么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'" 
+0

谢谢你,伊格纳西奥,做到了! – dotancohen

0

为什么低代用品DCC3应该用utf-8编码?这是不允许和无用的,因为代理不是一个字符。找到属于低代理的高代理项,解码其代码点,然后为代码点创建适当的utf-8序列。

+0

谢谢布莱迪。什么是DCC3?我试图寻找它可能是什么,但我没有看到任何相关的东西。我也不明白答案的其余部分,但希望在了解DCC3之后,我能够理解它。谢谢。 – dotancohen

+0

http://www.python.org/dev/peps/pep-0383/ –

+0

好吧,我会解释它。关于utf-16,我们讨论一串文字,好吧。一个单词有16位,这就是为什么有名字utf-16。现在,范围U + DC00和U + DFFF中的单词是低代理,范围U + D800和U + DBFF中的单词是高代理。这就是为什么0xDCC3是一个低代理,理解? – brighty

3

孤独的替代不应以UTF-8编码 - 这就是为什么它被用于无效输入的内部表示。

在现实生活中,获取数据对于“应该”所处的编码无效是非常常见的。例如,这个问题受到文本的启发,该文本看起来在Latin-1中,当ASCII或预期UTF-8。我把“假设”放在引号中,因为“编码信息”只是一种猜测,可能与实际文件无关,这很常见。

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

解码错误=替换会将该行变成“Zo's Coffee House”,这是一个改进。 (好吧,除非你试图用无效的字符替换无效的字符 - 而官方的unicode替换字符在ASCII中无效,这就是为什么'?'通常用于编码的原因。)

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

使用不成对的代理项允许Python存储无效字节而不会额外转义。准确地说,因为未配对的替代品是无效的,它们将永远不会出现在有效的输入中。 (如果它们以任何方式出现,它们将被解释为一对无法识别的字节,这两个字节被保留用于输出。)

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