Python3 utf-8 decodificar problema

El siguiente código funciona bien con Python3 en mi máquina con Windows e imprime el carácter ‘é’:

data = b"\xc3\xa9" print(data.decode('utf-8')) 

Sin embargo, ejecutar el mismo en un contenedor docker basado en Ubuntu da como resultado:

 UnicodeEncodeError: 'ascii' codec can't encode character '\xe9' in position 0: ordinal not in range(128) 

¿Hay algo que deba instalar para habilitar la deencoding de utf-8?

El problema es con la expresión print() , no con el método decode() . Si observa detenidamente, la excepción que se genera es un Unicode En codeError, no un – De codeError.

Cada vez que utiliza la función print() , Python convierte sus argumentos en una str y posteriormente codifica el resultado en bytes , que se envían al terminal (o lo que sea que se ejecute en Python). El códec que se utiliza para la encoding (por ejemplo, UTF-8 o ASCII) depende del entorno. En un caso ideal,

  • el códec que utiliza Python es compatible con el que espera el terminal, por lo que los caracteres se muestran correctamente (de lo contrario, obtienes un mojibake como “é” en lugar de “é”);
  • el códec utilizado cubre un rango de caracteres que es suficiente para sus necesidades (como UTF-8 o UTF-16, que contienen todos los caracteres).

En su caso, la segunda condición no se cumple para la ventana acoplable de Linux que menciona: la encoding utilizada es ASCII, que solo admite caracteres encontrados en una máquina de escribir inglesa antigua. Estas son algunas opciones para abordar este problema:

  • Establecer variables de entorno: en Linux, los valores predeterminados de encoding de Python dependen de esto (al menos parcialmente). En mi experiencia, esto es un poco de prueba y error; establecer LC_ALL en algo que contiene “UTF-8” funcionó para mí una vez. Tendrá que ponerlos en el script de inicio para el shell que ejecuta su terminal, por ejemplo. .bashrc .
  • Vuelva a codificar STDOUT, así:

     sys.stdout = open(sys.stdout.buffer.fileno(), 'w', encoding='utf8') 

    La encoding utilizada debe coincidir con la del terminal.

  • Codifique las cadenas usted mismo y envíelos al búfer binario subyacente a sys.stdout , por ejemplo. sys.stdout.buffer.write("é".encode('utf8')) . Esto es, por supuesto, mucho más repetitivo que print("é") . De nuevo, la encoding utilizada debe coincidir con la del terminal.
  • Evite print() completo. Use open(fn, encoding=...) para la salida, el módulo de registro para la información de progreso, dependiendo de qué tan interactivo sea su script, esto podría valer la pena (es cierto que probablemente enfrentará el mismo problema de encoding al escribir en STDERR con el módulo de registro).

Puede haber otras opciones, pero dudo que haya mejores.

Parece que Ubuntu, según la versión, utiliza una encoding u otra como predeterminada, y puede variar entre shell y python también. Adoptado de esta publicación y también de este blog :

Por lo tanto, la forma recomendada parece ser decirle a tu instancia de Python que use utf-8 como encoding predeterminada:

Establezca su encoding predeterminada de los archivos fuente de Python a través de la variable de entorno:

 export PYTHONIOENCODING=utf8 

Además, en los archivos de origen puede indicar la encoding que prefiere usar explícitamente, por lo que debería funcionar independientemente de la configuración del entorno (consulte esta pregunta + respuesta , documentos de Python y PEP 263 :

 #!/usr/bin/env python3 # -*- coding: utf-8 -*- .... 

Con respecto a la interpretación de la encoding de los archivos leídos por python, puede especificarlo explícitamente en el comando de abrir

 with open(fname, "rt", encoding="utf-8") as f: ... 

y hay una forma más intrincada con algunos efectos secundarios, pero te permite especificarlo explícitamente cada vez

 import sys # sys.setdefaultencoding() does not exist, here! reload(sys) # Reload does the trick! sys.setdefaultencoding('UTF8') 

Lea las advertencias sobre este truco en la respuesta y los comentarios relacionados .