Python 3 UnicodeDecodeError - ¿Cómo depuro UnicodeDecodeError?
Tengo un archivo de texto que el editor (la Comisión de Bolsa de Valores de EE. UU.) Afirma está codificado en UTF-8 (https://www.sec.gov/files/aqfs.pdf, Sección 4). Estoy procesando las líneas con el siguiente código:
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)
Recibo el siguiente error:
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
Dado que probablemente no pueda volver a la SEC y decirles que tienen archivos que no parecen estar codificados en UTF-8, ¿cómo debo depurar y detectar este error?
Que he probado
Hice un volcado hexadecimal del archivo y descubrí que el texto ofensivo era el texto "DIVULGACIÓN SUPLEMENTARIA DE INVERSIONES SIN CAJÓN". Si decodifico el byte infractor como un punto de código hexadecimal (es decir, "U + 00AD"), tiene sentido en contexto, ya que es el guión suave. Pero lo siguiente no parece funcionar:
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
he usadoerrors='replace'
, que parece pasar. Pero me gustaría entender qué sucederá si intento insertar eso en una base de datos.
Editado para agregar hexdump:
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|