【发布时间】:2018-02-21 03:58:39
【问题描述】:
我有一个文本文件,出版商(美国证券交易委员会)声称它是用 UTF-8 编码的(https://www.sec.gov/files/aqfs.pdf,第 4 节)。我正在使用以下代码处理这些行:
def tags(filename):
"""Yield Tag instances from tag.txt."""
with codecs.open(filename, 'r', encoding='utf-8', errors='strict') as f:
fields = f.readline().strip().split('\t')
for line in f.readlines():
yield process_tag_record(fields, line)
我收到以下错误:
Traceback (most recent call last):
File "/home/randm/Projects/finance/secxbrl.py", line 151, in <module>
main()
File "/home/randm/Projects/finance/secxbrl.py", line 143, in main
all_tags = list(tags("tag.txt"))
File "/home/randm/Projects/finance/secxbrl.py", line 109, in tags
content = f.read()
File "/home/randm/Libraries/anaconda3/lib/python3.6/codecs.py", line 698, in read
return self.reader.read(size)
File "/home/randm/Libraries/anaconda3/lib/python3.6/codecs.py", line 501, in read
newchars, decodedbytes = self.decode(data, self.errors)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xad in position 3583587: invalid start byte
鉴于我可能无法返回 SEC 并告诉他们他们的文件似乎不是以 UTF-8 编码的,我应该如何调试并捕获此错误?
我尝试了什么
我对文件进行了十六进制转储,发现有问题的文字是“非现金投资的补充披露”。如果我将违规字节解码为十六进制代码点(即“U+00AD”),则在上下文中是有意义的,因为它是软连字符。但以下似乎不起作用:
Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> b"\x41".decode("utf-8")
'A'
>>> b"\xad".decode("utf-8")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec cant decode byte 0xad in position 0: invalid start byte
>>> b"\xc2ad".decode("utf-8")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec cant decode byte 0xc2 in position 0: invalid continuation byte
我用过errors='replace',似乎通过了。但我想了解如果我尝试将其插入数据库会发生什么。
十六进制转储:
0036ae40 31 09 09 09 09 53 55 50 50 4c 45 4d 45 4e 54 41 |1....SUPPLEMENTA|
0036ae50 4c 20 44 49 53 43 4c 4f 53 55 52 45 20 4f 46 20 |L DISCLOSURE OF |
0036ae60 4e 4f 4e ad 43 41 53 48 20 49 4e 56 45 53 54 49 |NON.CASH INVESTI|
0036ae70 4e 47 20 41 4e 44 20 46 49 4e 41 4e 43 49 4e 47 |NG AND FINANCING|
0036ae80 20 41 43 54 49 56 49 54 49 45 53 3a 09 0a 50 72 | ACTIVITIES:..Pr|
【问题讨论】:
-
在 Python 3.6 中,不要使用
codecs.open()。标准的open()函数可以更好更快地处理编码数据。 -
实际的 hexdump 显示了什么? 十六进制,不是ASCII加替换字符。 U+00AD 字节将被编码为两个字节,0xC2 0xAD,因此您缺少 0xC2 字节。
-
你是如何获取数据文件的?如果那里缺少一个字节,则可能还有其他数据损坏。
-
接下来,我也不会使用
readline()和readlines()电话;使用fields = next(f).strip().split('\t')和for line in f:。这样可以避免在处理每一行之前立即将整个文件读入内存。 -
@HåkenLid:除了没有已知的编码可以产生 SEC 产生的输出。他们生成了无效的编解码器。
标签: python python-3.x unicode utf-8 character-encoding