Estoy usando este código para obtener una salida 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 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 para eso era el método binascii.b2a_qp () , pero cuando lo probé, 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'
¿Cómo convierto el valor de bytes de nuevo a cadena? Quiero decir, usar las "baterías" en lugar de hacerlo manualmente. Y me gustaría que estuviera bien con Python 3.
python
string
python-3.x
Tomás Sedovic
fuente
fuente
str(text_bytes)
funciona? Esto me parece extraño.str(text_bytes)
no se puede especificar la codificación. Dependiendo de lo que hay en text_bytes,text_bytes.decode('cp1250
) `podría resultar en una cadena muy diferente atext_bytes.decode('utf-8')
.str
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 flojo para leer por qué. Simplemente conviértaloutf-8
y vea si su código funciona. por ejemplovar = var.decode('utf-8')
unicode_text = str(bytestring, character_encoding)
funciona como se esperaba en Python 3. Aunqueunicode_text = bytestring.decode(character_encoding)
es más preferible evitar la confusión con solostr(bytes_obj)
eso produce una representación de texto enbytes_obj
lugar de decodificarlo en texto:str(b'\xb6', 'cp1252') == b'\xb6'.decode('cp1252') == '¶'
ystr(b'\xb6') == "b'\\xb6'" == repr(b'\xb6') != '¶'
Respuestas:
Necesita decodificar el objeto de bytes para producir una cadena:
fuente
"windows-1252"
tampoco es confiable (por ejemplo, para versiones de Windows en otros idiomas), ¿no sería mejor usarlosys.stdout.encoding
?b"\x80\x02\x03".decode("utf-8")
->UnicodeDecodeError: 'utf8' codec can't decode byte 0x80 in position 0: invalid start byte
.utf-8
es probable que la conversión falle. En su lugar, consulte la respuesta @techtonik (a continuación) stackoverflow.com/a/27527728/198536Debe decodificar la cadena de bytes y convertirla en una cadena de caracteres (Unicode).
En Python 2
o
En Python 3
o
fuente
variable = b'hello'
, entoncesunicode_text = variable.decode(character_encoding)
Creo que de esta manera es fácil:
fuente
bytes([112, 52, 52])
- btw bytes es un mal nombre para una variable local exactamente porque es un p3 incorporadoSi no conoce la codificación, para leer la entrada binaria en una cadena en forma compatible con Python 3 y Python 2, use la antigua codificación CP437 de MS-DOS :
Como la codificación es desconocida, 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 byte único y UTF-8).La decodificación de la entrada binaria arbitraria a UTF-8 no es segura, porque puede obtener esto:
Lo mismo se aplica a
latin-1
, que 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 infameordinal 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 confiabilidad.ACTUALIZACIÓN 20170116 : Gracias a los comentarios de Nearoo: también existe la posibilidad de escapar de todos los bytes desconocidos con
backslashreplace
un controlador de errores. Eso funciona solo para Python 3, por lo que incluso con esta solución aún obtendrá resultados inconsistentes de diferentes versiones de Python:Ver Soporte Unicode de Python para más detalles.
ACTUALIZACIÓN 20170119 : Decidí implementar una decodificación de escape de barra que funciona tanto para Python 2 como para Python 3. Debería ser más lenta que la
cp437
solución, pero debería producir resultados idénticos en cada versión de Python.fuente
b'\x00\x01\xffsd'.decode('utf-8', 'ignore')
Python 3.b'\x80abc'.decode("utf-8", "backslashreplace")
dará como resultado'\\x80abc'
. Esta información se tomó de la página de documentación Unicode que parece haberse actualizado desde la redacción de esta respuesta.En Python 3 , la codificación predeterminada es
"utf-8"
, por lo que puede usar directamente:que es equivalente a
Por otro lado, en Python 2 , la codificación predeterminada es la codificación de cadena predeterminada. Por lo tanto, debe usar:
¿Dónde
encoding
está la codificación que quieres?Nota: se agregó soporte para argumentos de palabras clave en Python 2.7.
fuente
Creo que realmente quieres esto:
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 marcará la diferencia.
Por cierto, el hecho de que sí importa es la razón por la que Python se movió para usar dos tipos diferentes de datos binarios y de texto: no puede convertir mágicamente entre ellos, ¡porque no conoce la codificación a menos que usted lo diga! La única forma en que USTED sabría es leer la documentación de Windows (o leerla aquí).
fuente
open()
función para secuencias de texto oPopen()
si lo pasauniversal_newlines=True
decida mágicamente la codificación de caracteres por usted (locale.getpreferredencoding(False)
en Python 3.3+).'latin-1'
es una codificación literal con todos los puntos de código establecidos, por lo que puede usarla para leer de manera efectiva una cadena de bytes en cualquier tipo de cadena que su Python admita (de manera literal en Python 2, en Unicode para Python 3).'latin-1'
es una buena manera de obtener mojibake. También hay sustitución mágica en Windows: es sorprendentemente difícil canalizar datos de un proceso a otro sin modificar, por ejemplodir
:\xb6
->\x14
(el ejemplo al final de mi respuesta)Establezca universal_newlines en True, es decir
fuente
text=True
lugar deuniversal_newlines=True
.Si bien la respuesta de @Aaron Maenpaa simplemente funciona, un usuario recientemente preguntó :
Puedes usar:
decode()
tiene un argumento estándar :fuente
.decode()
ese uso'utf-8'
puede fallar (la salida del comando puede usar una codificación de caracteres diferente o incluso devolver una secuencia de bytes no codificable). Aunque si la entrada es ascii (un subconjunto de utf-8) entonces.decode()
funciona.Para interpretar una secuencia de bytes como un texto, debe conocer la codificación de caracteres correspondiente:
Ejemplo:
ls
El comando puede producir resultados que no se pueden interpretar como texto. Los nombres de archivo en Unix pueden ser cualquier secuencia de bytes, excepto la barra diagonalb'/'
y cerob'\0'
:Intentando decodificar tal sopa de bytes usando los aumentos de codificación utf-8
UnicodeDecodeError
.Puede ser peor La decodificación puede fallar en silencio y producir mojibake si usa una codificación incompatible incorrecta:
Los datos están dañados pero su programa no se da cuenta de que se ha producido un error.
En general, qué codificación de caracteres utilizar no está incrustada en la secuencia de bytes en sí. 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 solo 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 laos.fsdecode()
función que tiene éxito incluso para nombres de archivo no codificables (usasys.getfilesystemencoding()
ysurrogateescape
controlador de errores en Unix):Para obtener los bytes originales, puede usar
os.fsencode()
.Si pasa el
universal_newlines=True
parámetro, entoncessubprocess
usalocale.getpreferredencoding(False)
para decodificar bytes, por ejemplo, puede estarcp1252
en Windows.Para decodificar el flujo de bytes sobre la marcha,
io.TextIOWrapper()
podría usarse: ejemplo .Los diferentes comandos pueden usar diferentes codificaciones de caracteres para su salida, por ejemplo,
dir
el comando interno (cmd
) puede usar cp437. Para decodificar su salida, puede pasar la codificación explícitamente (Python 3.6+):Los nombres de los archivos pueden diferir de
os.listdir()
(que usa la API de Windows Unicode), por ejemplo,'\xb6'
se pueden sustituir con'\x14'
los mapas de códec cp437 de Pythonb'\x14'
para controlar el carácter U + 0014 en lugar de U + 00B6 (¶). Para admitir nombres de archivo con caracteres Unicode arbitrarios, consulte Decodificar la salida de PowerShell que posiblemente contenga caracteres Unicode no ASCII en una cadena de Pythonfuente
Dado que esta pregunta es realmente sobre la
subprocess
salida, tiene un enfoque más directo disponible ya quePopen
acepta una palabra clave de codificación (en Python 3.6+):La respuesta general para otros usuarios es decodificar bytes en texto:
Sin argumento,
sys.getdefaultencoding()
será utilizado. Si sus datos no lo sonsys.getdefaultencoding()
, debe especificar la codificación explícitamente en ladecode
llamada:fuente
text=True
a decodificar stdin, stdout y stderr usando la codificación dada (si está configurada) o el sistema predeterminado de lo contrario.Popen(['ls', '-l'], stdout=PIPE, text=True)
.ls
salida de decodificación usandoutf-8
codificación puede fallar (ver ejemplo en mi respuesta de 2016 ).encoding
se proporciona eltext
parámetro , entonces el parámetro se ignora.Si debe obtener lo siguiente intentando
decode()
:También puede especificar el tipo de codificación directamente en un molde:
fuente
Cuando trabajo con datos de sistemas Windows (con
\r\n
terminaciones de línea), mi respuesta es¿Por qué? Pruebe esto con un Input.txt multilínea:
Todas las terminaciones de línea se duplicarán (a
\r\r\n
), lo que dará lugar a líneas vacías adicionales. Las funciones de lectura de texto de Python normalmente normalizan las terminaciones de línea para que las cadenas solo se usen\n
. Si recibe datos binarios de un sistema Windows, Python no tiene la oportunidad de hacerlo. Así,replicará su archivo original.
fuente
.replace("\r\n", "\n")
adiciones tanto tiempo. Esta es la respuesta si desea representar HTML correctamente.Hice una función para limpiar una lista
fuente
.strip
,.replace
,.encode
llamadas, etc en una lista por comprensión y sólo iterar sobre la lista una vez en lugar de la iteración más de cinco veces.Para Python 3, este es un enfoque mucho más seguro y pitónico para convertir de
byte
astring
:Salida:
fuente
byte_to_str
", lo que implica que devolverá un str, pero solo imprime el valor convertido e imprime un mensaje de error si falla (pero no genera una excepción). Este enfoque tampoco es propónico y ofusca labytes.decode
solución que proporcionó.Desde sys: parámetros y funciones específicos del sistema :
Para escribir o leer datos binarios desde / hacia las secuencias estándar, use el búfer binario subyacente. Por ejemplo, para escribir bytes en stdout, use
sys.stdout.buffer.write(b'abc')
.fuente
bytes
.fuente
Para su caso específico de "ejecutar un comando de shell y obtener su salida como texto en lugar de bytes", en Python 3.7, debe usar
subprocess.run
y pasartext=True
(así comocapture_output=True
capturar la salida)text
solía llamarseuniversal_newlines
y se cambió (bueno, con alias) en Python 3.7. Si desea admitir versiones de Python anteriores a 3.7, pase enuniversal_newlines=True
lugar detext=True
fuente
Si desea convertir cualquier byte, no solo la cadena convertida a bytes:
Sin embargo, esto no es muy eficiente. Convierte una imagen de 2 MB en 9 MB.
fuente
prueba esto
fuente