Convierte bytes en una cadena en python 3

8 minutos de lectura

Avatar de usuario de Tomas Sedovic
Tomás Sedovic

Capturé la salida estándar de un programa externo en un bytes objeto:

>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
>>>
>>> command_stdout
b'total 0\n-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file1\n-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file2\n'

Quiero convertir eso en una cadena normal de Python, para poder imprimirlo así:

>>> print(command_stdout)
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file1
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file2

¿Cómo convierto el bytes objetar a un str con pitón 3?


Consulte ¿La mejor manera de convertir cadenas en bytes en Python 3? por lo contrario.

  • por qué no str(text_bytes) ¿trabajar? Esto me parece extraño.

    –Charlie Parker

    14/03/2019 a las 22:25

  • @CharlieParker Porque str(text_bytes) no se puede especificar la codificación. Dependiendo de lo que haya en text_bytes, text_bytes.decode('cp1250)` podría resultar en una cadena muy diferente a text_bytes.decode('utf-8').

    –Craig Anderson

    31 de marzo de 2019 a las 17:32


  • entonces str la función ya no se convierte en una cadena real. Uno TIENE que decir una codificación explícitamente por alguna razón, soy demasiado perezoso para leer por qué. Solo conviértelo a utf-8 y ver si su código funciona. p.ej var = var.decode('utf-8')

    –Charlie Parker

    22 de abril de 2019 a las 23:32


  • @CraigAnderson: unicode_text = str(bytestring, character_encoding) funciona como se esperaba en Python 3. Aunque unicode_text = bytestring.decode(character_encoding) es preferible evitar confusiones con sólo str(bytes_obj) que produce una representación de texto para bytes_obj en lugar de decodificarlo a texto: str(b'\xb6', 'cp1252') == b'\xb6'.decode('cp1252') == '¶' y str(b'\xb6') == "b'\\xb6'" == repr(b'\xb6') != '¶'

    – jfs

    12 de abril de 2020 a las 5:11

  • Además, puedes pasar text=True a subprocess.run() o .Popen() y luego obtendrá una cadena de vuelta, sin necesidad de convertir bytes. O especificar encoding="utf-8" a cualquiera de las dos funciones.

    –David Gilbertson

    13 de septiembre de 2022 a las 5:46

Avatar de usuario de Aaron Maenpaa
Aarón Maenpaa

Decodificar el bytes objeto para producir una cadena:

>>> b"abcde".decode("utf-8") 
'abcde'

El ejemplo anterior asume que el bytes El objeto está en UTF-8, porque es una codificación común. Sin embargo, ¡debe usar la codificación en la que están realmente sus datos!

  • Sí, pero dado que este es el resultado de un comando de Windows, ¿no debería usar “.decode(‘windows-1252’)” en su lugar?

    – mcherm

    18 de julio de 2011 a las 19:48

  • Usando "windows-1252" tampoco es confiable (por ejemplo, para otras versiones de idioma de Windows), ¿no sería mejor usar sys.stdout.encoding?

    – Niko

    3 de enero de 2012 a las 15:20

  • Tal vez esto ayude a alguien más: a veces usa una matriz de bytes para la comunicación ex TCP. Si desea convertir una matriz de bytes en una cadena que corta los caracteres finales ‘\ x00′, la siguiente respuesta no es suficiente. Use b’example\x00\x00’.decode(‘utf-8’).strip(‘\x00’) entonces.

    – Wookie88

    16 de abril de 2013 a las 13:27

  • Documentación oficial para esto: para todos bytes y bytearray operaciones (métodos que se pueden llamar en estos objetos), ver aquí: docs.python.org/3/library/stdtypes.html#bytes-methods. Para bytes.decode() en particular, ver aquí: docs.python.org/3/library/stdtypes.html#bytes.decode.

    – Gabriel grapas

    25 de marzo de 2021 a las 4:12


Avatar de usuario de dF.
dF.

Decodifique la cadena de bytes y conviértala en una cadena de caracteres (Unicode).


Pitón 3:

encoding = 'utf-8'
b'hello'.decode(encoding)

o

str(b'hello', encoding)

Pitón 2:

encoding = 'utf-8'
'hello'.decode(encoding)

o

unicode('hello', encoding)

Avatar de usuario de Sisso
Sisso

Esto une una lista de bytes en una cadena:

>>> bytes_data = [112, 52, 52]
>>> "".join(map(chr, bytes_data))
'p44'

  • @leetNightshade: sin embargo, es terriblemente ineficiente. Si tiene una matriz de bytes, solo necesita decodificar.

    – Martijn Pieters

    1 de septiembre de 2014 a las 16:25

  • @Sasszem: este método es una forma pervertida de expresar: a.decode('latin-1') dónde a = bytearray([112, 52, 52]) (“No existe tal cosa como texto sin formato”. Si logró convertir bytes en una cadena de texto, entonces usó alguna codificación:latin-1 en este caso)

    – jfs

    16 de noviembre de 2016 a las 3:16

  • @leetNightshade: En aras de la exhaustividad: bytes(list_of_integers).decode('ascii') es aproximadamente 1/3 más rápido que ''.join(map(chr, list_of_integers)) en Phyton 3.6.

    – Martijn Pieters

    3 de julio de 2018 a las 12:01


avatar de usuario de anatoly techtonik
anatoly techtonik

Si no conoce la codificación, entonces para leer la entrada binaria en una cadena en una forma compatible con Python 3 y Python 2, use el antiguo MS-DOS CP437 codificación:

PY3K = sys.version_info >= (3, 0)

lines = []
for line in stream:
    if not PY3K:
        lines.append(line)
    else:
        lines.append(line.decode('cp437'))

Debido a que se desconoce la codificación, espere que los símbolos que no están en inglés se traduzcan a caracteres de cp437 (Los caracteres en inglés no se traducen porque coinciden en la mayoría de las codificaciones de un solo byte y UTF-8).

La decodificación de una entrada binaria arbitraria a UTF-8 no es segura, porque puede obtener esto:

>>> b'\x00\x01\xffsd'.decode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 2: invalid
start byte

Lo mismo se aplica a latin-1que era popular (¿el predeterminado?) para Python 2. Vea los puntos que faltan en Diseño de página de códigos – es donde Python se ahoga con infame ordinal not in range.

ACTUALIZACIÓN 20150604: Hay rumores de que Python 3 tiene la surrogateescape estrategia de error para codificar cosas en datos binarios sin pérdida de datos y fallas, pero necesita pruebas de conversión, [binary] -> [str] -> [binary]para validar tanto el rendimiento como la fiabilidad.

ACTUALIZACIÓN 20170116: Gracias al comentario de Nearoo: también existe la posibilidad de recortar todos los bytes desconocidos con escape backslashreplace controlador de errores Eso funciona solo para Python 3, por lo que, incluso con esta solución, seguirá obteniendo resultados inconsistentes de diferentes versiones de Python:

PY3K = sys.version_info >= (3, 0)

lines = []
for line in stream:
    if not PY3K:
        lines.append(line)
    else:
        lines.append(line.decode('utf-8', 'backslashreplace'))

Ver Compatibilidad con Unicode de Python para detalles.

ACTUALIZACIÓN 20170119: Decidí implementar la decodificación de escape de barra que funciona tanto para Python 2 como para Python 3. Debería ser más lento que el cp437 solución, pero debería producir resultados idénticos en cada versión de Python.

# --- preparation

import codecs

def slashescape(err):
    """ codecs error handler. err is UnicodeDecode instance. return
    a tuple with a replacement for the unencodable part of the input
    and a position where encoding should continue"""
    #print err, dir(err), err.start, err.end, err.object[:err.start]
    thebyte = err.object[err.start:err.end]
    repl = u'\\x'+hex(ord(thebyte))[2:]
    return (repl, err.end)

codecs.register_error('slashescape', slashescape)

# --- processing

stream = [b'\x80abc']

lines = []
for line in stream:
    lines.append(line.decode('utf-8', 'slashescape'))

avatar de usuario de lmiguelvargasf
miguelvargasf

en pitón 3la codificación predeterminada es "utf-8"por lo que puede usar directamente:

b'hello'.decode()

que es equivalente a

b'hello'.decode(encoding="utf-8")

Por otro lado, en pitón 2, la codificación tiene como valor predeterminado la codificación de cadena predeterminada. Por lo tanto, debe utilizar:

b'hello'.decode(encoding)

dónde encoding es la codificación que desea.

Nota: Se agregó soporte para argumentos de palabras clave en Python 2.7.

Avatar de usuario de Peter Mortensen
Pedro Mortensen

Creo que realmente quieres esto:

>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
>>> command_text = command_stdout.decode(encoding='windows-1252')

La respuesta de Aaron fue correcta, excepto que necesitas saber cual codificación a utilizar. Y creo que Windows usa ‘windows-1252’. Solo importará si tiene algunos caracteres inusuales (no ASCII) en su contenido, pero luego marcará la diferencia.

Por cierto, el hecho de que hace La cuestión es la razón por la que Python pasó a usar dos tipos diferentes para datos binarios y de texto: no puede convertir mágicamente entre ellos, ¡porque no conoce la codificación a menos que usted se lo diga! La única manera de saberlo es leer la documentación de Windows (o leerla aquí).

Dado que esta pregunta en realidad se refiere a subprocess salida, tiene enfoques más directos disponibles. Lo más moderno sería usar subprocess.check_output y pasando text=True (Python 3.7+) para decodificar automáticamente la salida estándar utilizando la codificación predeterminada del sistema:

text = subprocess.check_output(["ls", "-l"], text=True)

Para Python 3.6, Popen acepta un codificación palabra clave:

>>> from subprocess import Popen, PIPE
>>> text = Popen(['ls', '-l'], stdout=PIPE, encoding='utf-8').communicate()[0]
>>> type(text)
str
>>> print(text)
total 0
-rw-r--r-- 1 wim badger 0 May 31 12:45 some_file.txt

La respuesta general a la pregunta del título, si no se trata de la salida de un subproceso, es descodificar bytes a texto:

>>> b'abcde'.decode()
'abcde'

Sin argumento, sys.getdefaultencoding() se utilizará. Si sus datos no están sys.getdefaultencoding()entonces debe especificar la codificación explícitamente en el decode llamar:

>>> b'caf\xe9'.decode('cp1250')
'café'

¿Ha sido útil esta solución?