错误=代理转义vs错误=替换

时间:2019-06-04 09:45:01

标签: python file encoding utf-8

我正在尝试打开这样的文件:

with open("myfile.txt", encoding="utf-8") as f:

但是myfile.txt来自我应用程序的用户。而且有90%的时间,此文件以非UTF-8格式出现,导致应用程序退出,因为它无法正确读取文件。错误就像'utf-8' codec can't decode byte 0x9c

我已经在Google上进行了搜索,发现了一些Stackoverflow答案,说可以这样打开我的文件:

with open("myfile.txt", encoding="utf-8", errors="surrogateescape") as f:

但其他答案说要使用:

with open("myfile.txt", encoding="utf-8", errors="replace") as f:

那么errors="replace"errors="surrogateescape"之间有什么区别,哪一个可以修复文件中的非UTF-8字节?

2 个答案:

答案 0 :(得分:2)

医生说:

  

'替换':   用合适的替换标记物进行替换; Python将使用官方的U + FFFD REPLACEMENT CHARACTER用于解码时的内置编解码器,以及编码时的“?”。在replace_errors()中实现。
...
  'surrogateescape':在解码时,将字节替换为范围从U + DC80到U + DCFF的各个替代代码。当在编码数据时使用“ surrogateescape”错误处理程序时,此代码将被转换回相同的字节。 (有关详情,请参见PEP 383。)

这意味着使用replace,任何有问题的字节将被相同的U+FFFD替换字符替换,而使用surrogateescape,则将每个字节替换为不同的值。例如,将'\xe9'替换为'\udce9',将'\xe8'替换为'\udce8'

因此,使用replace时,您将获得有效的unicode字符,但会丢失文件的原始内容,而使用surrogateescape时,您可以知道原始字节(甚至可以使用.encode(errors='surrogateescape')进行完全重建),但是您的unicode字符串不正确,因为它包含原始代理代码。

长话短说:如果原始违规字节无所谓,而您只是想摆脱错误,那么replace是一个不错的选择,如果您需要保留它们以便以后处理,{{1 }}是必经之路。


surrogateescape具有非常好的功能,当您的文件主要包含ascii字符和一些(带重音)非ascii字符时。而且您还有一些用户有时会使用非UTF8编辑器来修改文件(或者无法声明UTF8编码)。在这种情况下,您将获得一个文件,该文件主要包含utf8数据和一些采用不同编码的字节,对于非英语西欧语言(例如法语,西班牙语的葡萄牙语)的Windows用户,通常为CP1252。在这种情况下,可以构建一个转换表,该转换表会将代理字符映射到cp1252字符集中的等效字符:

surrogateescape

然后您可以解码包含utf8和cp1252的mojibake的文件:

# first map all surrogates in the range 0xdc80-0xdcff to codes 0x80-0xff
tab0 = str.maketrans(''.join(range(0xdc80, 0xdd00)),
             ''.join(range(0x80, 0x100)))
# then decode all bytes in the range 0x80-0xff as cp1252, and map the undecoded ones
#  to latin1 (using previous transtable)
t = bytes(range(0x80, 0x100)).decode('cp1252', errors='surrogateescape').translate(tab0)
# finally use above string to build a transtable mapping surrogates in the range 0xdc80-0xdcff
#  to their cp1252 equivalent, or latin1 if byte has no value in cp1252 charset
tab = str.maketrans(''.join(chr(i) for i in range(0xdc80, 0xdd00)), t)

我已经成功地多次使用该方法来恢复以utf8格式生成并已在Windows计算机上用Excel编辑过的csv文件。

相同的方法可以用于其他从ascii导出的字符集

答案 1 :(得分:0)

我的问题是文件中的行具有混合的编码类型。

解决方法是删除encoding="utf-8"并添加errors="replace"。因此open()行的结尾将是这样:

with open("myfile.txt", errors="replace") as f:

如果可以检测文件的编码类型,我将其添加为encoding参数,但是很遗憾,无法检测到它。