pasar online from convertir convert codigo code python python-2.7 python-3.x encoding backwards-compatibility

online - python 2 to python 3



_Exact_ equivalente de `b ''...''.decode(" utf-8 "," backslashreplace ")` en Python 2 (2)

Puede escribir su propio controlador de errores. Aquí hay una solución que probé en Python 2.7, 3.3 y 3.6:

from __future__ import print_function import codecs import sys print(sys.version) def myreplace(ex): # The error handler receives the UnicodeDecodeError, which contains arguments of the # string and start/end indexes of the bad portion. bstr,start,end = ex.object,ex.start,ex.end # The return value is a tuple of Unicode string and the index to continue conversion. # Note: iterating byte strings returns int on 3.x but str on 2.x return u''''.join(''//x{:02x}''.format(c if isinstance(c,int) else ord(c)) for c in bstr[start:end]),end codecs.register_error(''myreplace'',myreplace) print(b''/xc2/xa1/xa1ABC''.decode("utf-8", "myreplace"))

Salida:

C:/>py -2.7 test.py 2.7.13 (v2.7.13:a06454b1afa1, Dec 17 2016, 20:42:59) [MSC v.1500 32 bit (Intel)] ¡/xa1ABC C:/>py -3.3 test.py 3.3.5 (v3.3.5:62cf4e77f785, Mar 9 2014, 10:35:05) [MSC v.1600 64 bit (AMD64)] ¡/xa1ABC C:/>py -3.6 test.py 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] ¡/xa1ABC

En Python .decode("utf-8", "backslashreplace") es una opción bastante buena para tratar con cadenas binarias parcialmente codificadas en Unicode, parcialmente desconocidas. Las secuencias UTF-8 válidas se decodificarán y las no válidas se conservarán como secuencias de escape. Por ejemplo

>>> print(b''/xc2/xa1/xa1''.decode("utf-8", "backslashreplace")) ¡/xa1

Esto pierde la distinción entre b''/xc2/xa1/xa1'' y b''/xc2/xa1//xa1'' , pero si estás en "solo b''/xc2/xa1//xa1'' algo no demasiado desagradable que pueda arreglar a mano más tarde" estado de ánimo, eso probablemente esté bien.

Sin embargo, esta es una nueva característica en Python 3.5. El programa en el que estoy trabajando también necesita soportar 3.4 y 2.7. En esas versiones, arroja una excepción:

>>> print(b''/xc2/xa1/xa1''.decode("utf-8", "backslashreplace")) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.7/encodings/utf_8.py", line 16, in decode return codecs.utf_8_decode(input, errors, True) TypeError: don''t know how to handle UnicodeDecodeError in error callback

He encontrado una aproximación, pero no un equivalente exacto:

>>> print(b''/xc2/xa1/xa1''.decode("latin1") ... .encode("ascii", "backslashreplace").decode("ascii")) /xc2/xa1/xa1

Es muy importante que el comportamiento no dependa de la versión del intérprete. ¿Alguien puede aconsejar una forma de obtener exactamente el comportamiento de Python 3.5 en 2.7 y 3.4?

(Las versiones anteriores de 2.x o 3.x no necesitan funcionar. Los codecs parche de mono son totalmente aceptables).


Intenté un respaldo más completo de la implementación de cpython

Esto maneja tanto UnicodeDecodeError (desde .decode() ) como UnicodeEncodeError desde .encode() y UnicodeTranslateError desde .translate() :

from __future__ import unicode_literals import codecs def _bytes_repr(c): """py2: bytes, py3: int""" if not isinstance(c, int): c = ord(c) return ''//x{:x}''.format(c) def _text_repr(c): d = ord(c) if d >= 0x10000: return ''//U{:08x}''.format(d) else: return ''//u{:04x}''.format(d) def backslashescape_backport(ex): s, start, end = ex.object, ex.start, ex.end c_repr = _bytes_repr if isinstance(ex, UnicodeDecodeError) else _text_repr return ''''.join(c_repr(c) for c in s[start:end]), end codecs.register_error(''backslashescape_backport'', backslashescape_backport) print(b''/xc2/xa1/xa1after''.decode(''utf-8'', ''backslashescape_backport'')) print(u''/u2603''.encode(''latin1'', ''backslashescape_backport''))