Как я должен декодировать байты (используя ASCII), не теряя байтов "мусора", если xmlcharrefreplace и backslashreplace не работают?
У меня есть сетевой ресурс, который возвращает мне данные, которые должны (согласно спецификациям) быть закодированной в ASCII строкой. Но в некоторых редких случаях я получаю мусорные данные.
Один ресурс, например, возвращает b'\xd3PS-90AC'
, тогда как другой ресурс для одного и того же ключа возвращает b'PS-90AC'
Первое значение содержит строку, отличную от ASCII. Очевидно, нарушение спецификации, но это, к сожалению, вне моего контроля. Никто из нас не уверен на 100%, что это действительно мусор или данные, которые следует сохранить.
Приложение, вызывающее удаленные ресурсы, сохраняет данные в локальной базе данных для ежедневного использования. Я мог бы просто сделать data.decode('ascii', 'replace')
или ..., 'ignore')
, но потом я потерял бы данные, которые впоследствии могут оказаться полезными.
Мой немедленный рефлекс должен был использовать 'xmlcharrefreplace'
или 'backslashreplace'
в качестве обработчика ошибок. Просто потому, что это приведет к отображению строки. Но затем я получаю следующую ошибку: TypeError: don't know how to handle UnicodeDecodeError in error callback
Единственный обработчик ошибок, который работал, был surrogateescape
, но это, по-видимому, предназначено для имен файлов. С другой стороны, для моих целей и целей это сработало.
Почему 'xmlcharrefreplace'
и 'backslashreplace'
не работают? Я не понимаю ошибку.
Например, ожидаемое выполнение:
>>> data = b'\xd3PS-90AC'
>>> new_data = data.decode('ascii', 'xmlcharrefreplace')
>>> print(repr(new_data))
'&#d3;PS-90AC'
Это надуманный пример. Моя цель - не потерять никаких данных. Если бы я использовал обработчик ошибок ignore
или replace
, байт, о котором идет речь, по существу исчезнет, а информация будет потеряна.
Ответы
Ответ 1
>>> data = b'\xd3PS-90AC'
>>> data.decode('ascii', 'surrogateescape')
'\udcd3PS-90AC'
Он не использует html-объекты, но является достойной отправной точкой. Если этого недостаточно, вам придется зарегистрировать свой собственный обработчик ошибок, используя codecs.register_error Я предполагаю.
Для Python3:
def handler(err):
start = err.start
end = err.end
return ("".join(["&#{0};".format(err.object[i]) for i in range(start,end)]),end)
import codecs
codecs.register_error('xmlcharreffallback', handler)
data = b'\xd3PS-90AC'
data.decode('ascii', 'xmlcharreffallback')
Для Python 2
def handler(err):
start = err.start
end = err.end
return (u"".join([u"&#{0};".format(ord(err.object[i])) for i in range(start,end)]),end)
import codecs
codecs.register_error('xmlcharreffallback', handler)
data = b'\xd3PS-90AC'
data.decode('ascii', 'xmlcharreffallback')
Оба производят:
'ÓPS-90AC'
Ответ 2
Для полноты, хотелось добавить, что с python 3.5, backslashreplace
работает для декодирования, поэтому вам больше не нужно добавлять настраиваемый обработчик ошибок.