我必须将文本文件读入Python。文件编码为:
file -bi test.csv
text/plain; charset=us-ascii
这是第三方文件,我每天都会收到一个新文件,所以我宁愿不改变它。该文件具有非ascii字符,例如Ö。我需要使用python读取行,并且我可以忽略具有非ascii字符的行。
我的问题是,当我用Python读取文件时,当到达存在非ascii字符的行时,我得到UnicodeDecodeError,而我无法读取文件的其余部分。
有没有办法避免这种情况。如果我试试这个:
fileHandle = codecs.open("test.csv", encoding='utf-8');
try:
for line in companiesFile:
print(line, end="");
except UnicodeDecodeError:
pass;
然后当达到错误时,for循环结束,我无法读取剩余的文件。我想跳过导致错误的行并继续。如果可能的话,我宁愿不对输入文件进行任何更改。
有没有办法做到这一点? 非常感谢你。
答案 0 :(得分:38)
您的文件似乎没有使用UTF-8编码。打开文件时使用正确的编解码器非常重要。
可告诉open()
如何使用errors
关键字处理解码错误:
errors 是一个可选字符串,用于指定如何处理编码和解码错误 - 这不能在二进制模式下使用。虽然已向
codecs.register_error()
注册的任何错误处理名称也有效,但可以使用各种标准错误处理程序。标准名称是:如果存在编码错误,
'strict'
会引发ValueError
异常。默认值None
具有相同的效果。'ignore'
忽略错误。请注意,忽略编码错误可能会导致数据丢失。'replace'
会导致替换标记(例如'?')插入格式错误的数据。- 只有在写入文件时才支持
'surrogateescape'
将表示任何不正确的字节,作为Unicode专用区中的代码点,范围从U + DC80到U + DCFF。当写入数据时使用surrogateescape
错误处理程序时,这些私有代码点将被转回相同的字节。这对于处理未知编码的文件非常有用。'xmlcharrefreplace'
。编码不支持的字符将替换为相应的XML字符引用&#nnn;
。'backslashreplace'
(也只在编写时支持)用Python的反斜杠转义序列替换不支持的字符。
使用'strict'
以外的任何内容('ignore'
,'replace'
等)打开文件,您就可以阅读该文件而不会引发异常。
请注意,解码是针对每个缓冲的数据块进行的,而不是按文本行进行。如果必须逐行检测错误,请使用surrogateescape
处理程序并测试代理范围内代码点读取的每一行:
import re
_surrogates = re.compile(r"[\uDC80-\uDCFF]")
def detect_decoding_errors_line(l, _s=_surrogates.finditer):
"""Return decoding errors in a line of text
Works with text lines decoded with the surrogateescape
error handler.
Returns a list of (pos, byte) tuples
"""
# DC80 - DCFF encode bad bytes 80-FF
return [(m.start(), bytes([ord(m.group()) - 0xDC00]))
for m in _s(l)]
E.g。
with open("test.csv", encoding="utf8", errors="surrogateescape") as f:
for i, line in enumerate(f, 1):
errors = detect_decoding_errors_line(line)
if errors:
print(f"Found errors on line {i}:")
for (col, b) in errors:
print(f" {col + 1:2d}: {b[0]:02x}")
考虑到并非所有解码错误都能从优雅中恢复。虽然UTF-8在面对小错误时设计得很稳健,但其他多字节编码(如UTF-16和UTF-32)无法应对丢弃或额外的字节,这将影响行分隔符的精确度可以找到。然后,上述方法可以导致文件的其余部分被视为一个长行。如果该文件足够大,那么如果该行文件“'”可能会导致MemoryError
异常。足够大了。