Pergunta

Estou usando este código para obter a saída padrão de um programa externo:

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

O comunicar () retorna uma 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'

No entanto, eu gostaria de trabalhar com a saída como uma string Python normal. Para que eu pudesse imprimi-lo como este:

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

Eu pensei que era isso o que o binascii.b2a_qp () método é para, mas quando eu tentei, eu tenho a mesma matriz de bytes novamente:

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

Alguém sabe como converter o valor bytes volta a corda? Quer dizer, usando as "baterias", em vez de fazê-lo manualmente. E eu gostaria que ele seja ok com Python 3.

Foi útil?

Solução

Você precisa decodificar os bytes objeto para produzir uma string:

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

Outras dicas

Eu acho que desta forma é fácil:

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

Você precisa decodificar a seqüência de byte e transformá-lo em um personagem (unicode) string.

Em Python 2

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

Em Python 3

encoding = 'utf-8'
str(b'hello', encoding)

Se você não sabe a codificação, em seguida, ler a entrada binário em seqüência em Python 3 e Python 2 maneira compatível, utilize MS-DOS antigos CP437 encoding:

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

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

Porque codificação é desconhecido, espera símbolos não-inglês para traduzir a personagens de cp437 (caracteres ingleses não são traduzidos, porque eles correspondem, na maioria dos codificações de byte único e UTF-8).

Decodificando entrada binária arbitrária para UTF-8 não é seguro, porque você pode obter esta:

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

O mesmo se aplica a latin-1, que era popular (default?) Para Python 2. Veja os pontos perdidos em Codepage layout -. é onde Python engasga com ordinal not in range infame

Atualizar 20150604 :. Há rumores de que Python 3 tem estratégia de erro surrogateescape para codificar o material em dados binários sem perda de dados e acidentes, mas precisa de testes de conversão [binary] -> [str] -> [binary] para validar o desempenho ea confiabilidade

Atualizar 20170116 : Graças ao comentário por Nearoo - há também a possibilidade de cortar escapar todos os bytes desconhecidos com manipulador de erro backslashreplace. Isso só funciona para Python 3, por isso mesmo com esta solução alternativa você ainda vai ter saída inconsistentes de diferentes versões do 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'))

Consulte https: //docs.python. org / 3 / howto / unicode.html #-s-unicode-suporte python para mais detalhes.

Atualizar 20170119 : I decidiu implementar barra escapar de decodificação que funciona tanto para Python 2 e Python 3. Deve ser mais lenta que a solução cp437, mas deve produzir resultados idênticos em cada versão 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'))

Em Python 3 , a codificação padrão é "utf-8", assim você pode usar diretamente:

b'hello'.decode()

o que equivale a

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

Por outro lado, em Python 2 , codificação padrões para a codificação de string padrão. Assim, você deve usar:

b'hello'.decode(encoding)

onde encoding é a codificação que deseja.

Nota: apoio para argumentos de palavra-chave foi adicionada no Python 2.7.

Eu acho que você realmente quer é o seguinte:

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

A resposta de Aaron estava correto, exceto que você precisa saber qual a codificação para uso. E eu acredito que usa o Windows 'windows-1252'. Só vai importa se você tem alguns caracteres incomuns (não-ASCII) em seu conteúdo, mas, em seguida, ele vai fazer a diferença.

A propósito, o fato de que realmente importa é a razão que Python se mudou para usando dois tipos diferentes de dados binários e texto: não pode converter magicamente entre eles, porque ele não sabe a codificação, a menos que você diga a ele ! A única maneira que você poderia saber é ler a documentação do Windows (ou lê-lo aqui).

Definir universal_newlines como verdadeiro, ou seja.

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

Enquanto a resposta de @ Aaron Mäenpää simplesmente funciona, um usuário recentemente pediu :

Existe alguma maneira mais simples? 'Fhand.read (). Decode ( "ASCII")' [...] É tão longa!

Você pode usar:

command_stdout.decode()

decode() tem um padrão argumento :

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

Para interpretar uma seqüência de bytes como um texto, você tem que saber o codificação de caracteres correspondente:

unicode_text = bytestring.decode(character_encoding)

Exemplo:

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

comando ls poderá produzir uma saída que não pode ser interpretado como texto. Os nomes dos arquivos em Unix pode ser qualquer sequência de bytes excepto b'/' barra e nulo b'\0':

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

Tentando descodificar tais sopa de byte, usando utf-8 codificação levanta UnicodeDecodeError.

Pode ser pior. A decodificação pode falhar silenciosamente e produzir mojibake se você usar uma codificação incompatíveis errado:

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

Os dados está corrompido, mas o seu programa permanece sem saber que uma falha Ocorreu.

Em geral, o que codificação de caracteres para utilização não é incorporado na própria seqüência de byte. Você tem que comunicar esta informação out-of-band. Alguns resultados são mais propensos do que outros e, portanto, módulo chardet existe que pode acho a codificação de caracteres. Um único script Python pode usar várias codificações de caracteres em lugares diferentes.


saída ls pode ser convertida para uma string Python utilizando os.fsdecode() função que sucede mesmo para undecodable nomes (ele usa sys.getfilesystemencoding() e erro surrogateescape manipulador on Unix):

import os
import subprocess

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

Para obter os bytes originais, você poderia usar os.fsencode().

Se você passar parâmetro universal_newlines=True então usos subprocess locale.getpreferredencoding(False) para descodificar bytes, por exemplo, pode ser cp1252 no Windows.

Para decodificar o fluxo de bytes on-the-fly, io.TextIOWrapper() poderia ser utilizado:. exemplo

comandos diferentes podem usar diferentes codificações de caracteres para a sua de saída, por exemplo, dir comando interno (cmd) pode utilizar CP437. Para decodificar a sua saída, você poderia passar a codificação explicitamente (Python 3.6 +):

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

Os nomes podem diferir os.listdir() (que usa o Windows Unicode API), por exemplo, '\xb6' pode ser substituído com '\x14'-Python CP437 codec mapeia b'\x14' para caractere de controle U + 0014 em vez de U + 00B6 (¶). Para nomes de ficheiros de apoio com arbitrárias caracteres Unicode, ver Descodificar poweshell saída possivelmente contendo caracteres Unicode não ASCII para uma cadeia pitão

Uma vez que esta questão é realmente perguntando sobre saída subprocess, você tem uma abordagem mais direta disponível desde Popen aceita um codificação palavra-chave (em 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

A resposta geral para outros usuários é a decodificação bytes para texto:

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

Com nenhum argumento, sys.getdefaultencoding() será usado. Se os dados não é sys.getdefaultencoding(), então você deve especificar a codificação explicitamente no decode chamada :

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

Se você deve obter o seguinte, tentando decode():

AttributeError: objeto 'str' tem nenhum atributo 'decodificação'

Você também pode especificar o tipo de codificação em linha reta em um molde:

>>> my_byte_str
b'Hello World'

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

Ao trabalhar com dados de sistemas Windows (com terminações de linha \r\n), minha resposta é

String = Bytes.decode("utf-8").replace("\r\n", "\n")

Por quê? Tente isto com uma multilinha Input.txt:

Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8")
open("Output.txt", "w").write(String)

Todos os finais de linha será duplicada (para \r\r\n), levando a linhas vazias extras. funções de leitura de texto geralmente finais de linha normalizar do Python para que as cordas usar somente \n. Se você receber dados binários de um sistema Windows, Python não tem uma chance de fazer isso. Assim,

Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8").replace("\r\n", "\n")
open("Output.txt", "w").write(String)

replicará o arquivo original.

Eu fiz uma função de limpar uma lista

def cleanLists(self, lista):
    lista = [x.strip() for x in lista]
    lista = [x.replace('\n', '') for x in lista]
    lista = [x.replace('\b', '') for x in lista]
    lista = [x.encode('utf8') for x in lista]
    lista = [x.decode('utf8') for x in lista]

    return lista

Para Python 3, este é um muito mais seguro e Pythonic abordagem converter de byte para string:

def byte_to_str(bytes_or_str):
    if isinstance(bytes_or_str, bytes): #check if its in bytes
        print(bytes_or_str.decode('utf-8'))
    else:
        print("Object not of byte type")

byte_to_str(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')

Output:

total 0
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file1
-rw-rw-r-- 1 thomas thomas 0 Mar  3 07:03 file2
def toString(string):    
    try:
        return v.decode("utf-8")
    except ValueError:
        return string

b = b'97.080.500'
s = '97.080.500'
print(toString(b))
print(toString(s))

Se você quiser converter qualquer bytes, não apenas corda convertidos em bytes:

with open("bytesfile", "rb") as infile:
    str = base64.b85encode(imageFile.read())

with open("bytesfile", "rb") as infile:
    str2 = json.dumps(list(infile.read()))

Isto não é muito eficiente, no entanto. Ele vai se transformar uma imagem 2 mb em 9 mb.

A partir http://docs.python.org/3/library/sys. html ,

Para escrever ou ler dados binários de / para os fluxos padrão, usar o buffer binário subjacente. Por exemplo, para escrever bytes para stdout, uso sys.stdout.buffer.write(b'abc').

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top