Pregunta Convertir bytes a una cadena?


Estoy usando este código para obtener un resultado estándar de un programa externo:

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

El método de comunicación () devuelve una matriz de bytes:

>>> 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'

Sin embargo, me gustaría trabajar con la salida como una cadena de Python normal. 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

Pensé que eso es lo que binascii.b2a_qp () El método es para, pero cuando lo intenté, obtuve el mismo conjunto de bytes nuevamente:

>>> binascii.b2a_qp(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'

¿Alguien sabe cómo convertir el valor de los bytes a cadena? Quiero decir, usar las "baterías" en lugar de hacerlo manualmente. Y me gustaría que esté bien con Python 3.


1236
2018-03-03 12:23


origen


Respuestas:


Necesita decodificar el objeto bytes para producir una cadena:

>>> b"abcde"
b'abcde'

# utf-8 is used here because it is a very common encoding, but you
# need to use the encoding your data is actually in.
>>> b"abcde".decode("utf-8") 
'abcde'

2036
2018-03-03 12:26



Creo que de esta manera es fácil:

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

119
2017-08-22 12:57



Necesita decodificar la cadena de bytes y convertirla en una cadena de caracteres (unicode).

b'hello'.decode(encoding)

o

str(b'hello', encoding)

99
2018-03-03 12:28



Si no conoce la codificación, entonces, para leer la entrada binaria en cadena en Python 3 y Python 2, use MS-DOS antiguo. 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 la codificación es desconocida, se espera que los símbolos que no están en inglés se traduzcan en caracteres de cp437 (Los caracteres en inglés no están traducidos, porque coinciden en la mayoría de las codificaciones de un solo byte y UTF-8).

La decodificación de 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 aplica a latin-1, que era popular (¿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 surrogateescape estrategia de error para codificar cosas en datos binarios sin pérdida de datos y bloqueos, pero necesita pruebas de conversión [binary] -> [str] -> [binary] para validar tanto el rendimiento como la fiabilidad.

ACTUALIZACIÓN 20170116: Gracias a los comentarios de Nearoo, también existe la posibilidad de eliminar todos los bytes desconocidos backslashreplace manejador de errores Eso funciona solo para Python 3, por lo que incluso con esta solución alternativa, obtendrá resultados incoherentes 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 https://docs.python.org/3/howto/unicode.html#python-s-unicode-support para detalles.

ACTUALIZACIÓN 20170119: Decidí implementar la descodificación de escape de barra que funciona tanto para Python 2 como para Python 3. Debería ser más lento que 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'))

57
2017-12-17 14:23



Creo que lo que realmente quieres es 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 necesita saber QUÉ codificación usar. Y creo que Windows usa 'windows-1252'. Solo importará si tiene algunos caracteres inusuales (no ascii) en su contenido, pero luego hará una diferencia.

Por cierto, el hecho de que SÍ importe es la razón por la cual Python pasó a usar dos tipos diferentes de datos binarios y de texto: ¡no puede convertirse mágicamente entre ellos porque no conoce la codificación a menos que usted lo diga! La única forma en que TÚ lo sabrías es leer la documentación de Windows (o leerla aquí).


32
2017-07-18 19:51



En Python 3, la codificación predeterminada es "utf-8", para que pueda usar directamente:

b'hello'.decode()

que es equivalente a

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

Por otra parte, en Python 2, la codificación predeterminada es la codificación de cadena predeterminada. Por lo tanto, debes usar:

b'hello'.decode(encoding)

dónde encoding es la codificación que quieres

Nota: soporte para argumentos de palabra clave fue agregado en Python 2.7.


30
2018-06-29 14:21



Establezca universal_newlines en True, es decir

command_stdout = Popen(['ls', '-l'], stdout=PIPE, universal_newlines=True).communicate()[0]

26
2018-01-21 15:31



Mientras Respuesta de @arón Maenpaa solo funciona, un usuario pedido recientemente

¿Hay alguna manera más sencilla? 'fhand.read (). decode ("ASCII")' [...] ¡Es tan largo!

Puedes usar

command_stdout.decode()

decode() tiene un argumento estándar

codecs.decode(obj, encoding='utf-8', errors='strict')


15
2017-11-13 10:24



Para interpretar una secuencia de bytes como un texto, debes conocer el codificación de caracteres correspondiente:

unicode_text = bytestring.decode(character_encoding)

Ejemplo:

>>> b'\xc2\xb5'.decode('utf-8')
'µ'

ls comando puede producir resultados que no se pueden interpretar como texto. Nombres de archivo en Unix puede ser cualquier secuencia de bytes, excepto la barra inclinada b'/' y cero b'\0':

>>> open(bytes(range(0x100)).translate(None, b'\0/'), 'w').close()

Intentando decodificar tal sopa de bytes usando aumentos de codificación utf-8 UnicodeDecodeError.

Puede ser peor La decodificación puede fallar silenciosamente y producir mojibake si usa una codificación incompatible incorrecta:

>>> '—'.encode('utf-8').decode('cp1252')
'—'

La información está corrupta pero su programa no sabe que una falla ha ocurrido.

En general, qué codificación de caracteres usar no está incrustada en la secuencia de bytes en sí misma. Tienes que comunicar esta información fuera de banda. Algunos resultados son más probables que otros y, por lo tanto, chardet existe un módulo que puede adivinar la codificación de caracteres. Un único script de Python puede usar codificaciones de caracteres múltiples en diferentes lugares.


ls la salida se puede convertir a una cadena de Python usando os.fsdecode() función que tiene éxito incluso para indecodificable nombres de archivo (usa sys.getfilesystemencoding() y surrogateescape controlador de errores en Unix):

import os
import subprocess

output = os.fsdecode(subprocess.check_output('ls'))

Para obtener los bytes originales, puede usar os.fsencode().

Si pasa universal_newlines=True parámetro entonces subprocess usos locale.getpreferredencoding(False) para decodificar bytes, por ejemplo, puede ser cp1252 en Windows.

Para decodificar la secuencia de bytes sobre la marcha, io.TextIOWrapper() puede ser usado: ejemplo.

Los diferentes comandos pueden usar diferentes codificaciones de caracteres para su salida, por ejemplo, dir comando interno (cmd) puede usar cp437. Para decodificar su salida, puede pasar la codificación explícitamente (Python 3.6+):

output = subprocess.check_output('dir', shell=True, encoding='cp437')

Los nombres de archivo pueden diferir de os.listdir() (que usa Windows API Unicode) por ejemplo, '\xb6' puede ser sustituido con '\x14'-Python cp437 códec mapas b'\x14' para controlar el carácter U + 0014 en lugar de U + 00B6 (¶). Para admitir nombres de archivos con caracteres Unicode arbitrarios, consulte Descodificar la salida Poweshell que posiblemente contenga caracteres no unicos Ascii en una cadena de Python


10
2017-11-16 09:43



Si debe obtener lo siguiente, intente decode():

AttributeError: 'str' object has no attribute 'decode'

También puede especificar el tipo de codificación directamente en un molde:

>>> my_byte_str
b'Hello World'

>>> str(my_byte_str, 'utf-8')
'Hello World'

5
2017-11-22 04:20



Dado que esta pregunta en realidad está preguntando sobre subprocess salida, tiene un enfoque más directo disponible desde Popen acepta una codificación palabra clave (en Python 3.6+):

>>> 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 para otros usuarios es descodificar bytes a texto:

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

Sin argumentos, sys.getdefaultencoding() se utilizará. Si tus datos no son sys.getdefaultencoding(), entonces debe especificar la codificación explícitamente en decode llamada:

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

5
2018-05-31 17:52