Estou usando esse código para obter saída padrão de um programa externo:
>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
O método communic () 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 assim:
>>> 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 é para isso que serve o método binascii.b2a_qp () , mas quando tentei, obtive 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'
Como faço para converter o valor de bytes novamente em string? Quero dizer, usando as "baterias" em vez de fazê-lo manualmente. E eu gostaria que tudo estivesse bem com o Python 3.
python
string
python-3.x
Tomas Sedovic
fonte
fonte
str(text_bytes)
funciona? Isso me parece bizarro.str(text_bytes)
não é possível especificar a codificação. Dependendo do conteúdo de text_bytes,text_bytes.decode('cp1250
) `pode resultar em uma string muito diferente detext_bytes.decode('utf-8')
.str
função não se converte mais em uma string real. É preciso dizer uma codificação explicitamente, por algum motivo, que tenho preguiça de ler o porquê. Basta convertê-loutf-8
e ver se seu código funciona. por exemplo,var = var.decode('utf-8')
unicode_text = str(bytestring, character_encoding)
funciona como esperado no Python 3. Emboraunicode_text = bytestring.decode(character_encoding)
seja mais preferível evitar confusão, apenasstr(bytes_obj)
isso produz uma representação de texto para, embytes_obj
vez de decodificá-la para texto:str(b'\xb6', 'cp1252') == b'\xb6'.decode('cp1252') == '¶'
estr(b'\xb6') == "b'\\xb6'" == repr(b'\xb6') != '¶'
Respostas:
Você precisa decodificar o objeto bytes para produzir uma string:
fonte
"windows-1252"
também não é confiável (por exemplo, para versões em outros idiomas do Windows), não seria melhor usarsys.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
é provável que a conversão falhe. Em vez disso ver a resposta @techtonik (abaixo) stackoverflow.com/a/27527728/198536Você precisa decodificar a sequência de bytes e transformá-la em uma sequência de caracteres (Unicode).
No Python 2
ou
No Python 3
ou
fonte
variable = b'hello'
, entãounicode_text = variable.decode(character_encoding)
Eu acho assim fácil:
fonte
bytes([112, 52, 52])
- btw bytes é um nome ruim para uma variável local exatamente porque é um P3 builtinSe você não conhece a codificação, para ler a entrada binária na cadeia de caracteres de maneira compatível com Python 3 e Python 2, use a antiga codificação CP437 do MS-DOS :
Como a codificação é desconhecida, espere que símbolos não ingleses sejam traduzidos para caracteres de
cp437
(caracteres ingleses não são traduzidos, porque correspondem na maioria das codificações de byte único e UTF-8).A decodificação de entrada binária arbitrária para UTF-8 não é segura, pois você pode obter o seguinte:
O mesmo se aplica a
latin-1
, que era popular (o padrão?) Para o Python 2. Veja os pontos que faltam no Codepage Layout - é onde o Python se engasga com o famosoordinal not in range
.ATUALIZAÇÃO 20150604 : Há rumores de que o Python 3 tem a
surrogateescape
estratégia de erro para codificar coisas em dados binários sem perda de dados e falhas, mas precisa de testes de conversão[binary] -> [str] -> [binary]
para validar o desempenho e a confiabilidade.ATUALIZAÇÃO 20170116 : Graças ao comentário de Nearoo - também há a possibilidade de cortar com escape todos os bytes desconhecidos com o
backslashreplace
manipulador de erros. Isso funciona apenas para o Python 3, portanto, mesmo com essa solução alternativa, você ainda terá resultados inconsistentes de diferentes versões do Python:Veja Suporte Unicode do Python para obter detalhes.
ATUALIZAÇÃO 20170119 : Decidi implementar a decodificação de escape de barra que funciona tanto para o Python 2 quanto para o Python 3. Deve ser mais lento que a
cp437
solução, mas deve produzir resultados idênticos em todas as versões do Python.fonte
b'\x00\x01\xffsd'.decode('utf-8', 'ignore')
em python 3.b'\x80abc'.decode("utf-8", "backslashreplace")
resultará em'\\x80abc'
. Esta informação foi retirada da página de documentação unicode, que parece ter sido atualizada desde a redação desta resposta.No Python 3 , a codificação padrão é
"utf-8"
, então você pode usar diretamente:que é equivalente a
Por outro lado, no Python 2 , a codificação é padronizada com a codificação de string padrão. Portanto, você deve usar:
onde
encoding
está a codificação que você deseja.Nota: o suporte a argumentos de palavras-chave foi adicionado no Python 2.7.
fonte
Eu acho que você realmente quer isso:
A resposta de Aaron estava correta, exceto que você precisa saber qual codificação usar. E eu acredito que o Windows usa 'windows-1252'. Só importa se você tiver alguns caracteres incomuns (não ASCII) em seu conteúdo, mas isso fará a diferença.
By the way, o fato de que ele faz questão é 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 não sei a codificação, a menos que você diga a ele! A única maneira que você saberia é ler a documentação do Windows (ou leia aqui).
fonte
open()
para fluxos de texto ou,Popen()
se você passar,universal_newlines=True
decide magicamente a codificação de caracteres para você (locale.getpreferredencoding(False)
no Python 3.3 ou superior).'latin-1'
é uma codificação literal com todos os pontos de código definidos, para que você possa efetivamente ler uma sequência de bytes em qualquer tipo de sequência suportada pelo Python (portanto, literalmente no Python 2, no Unicode para Python 3).'latin-1'
é uma boa maneira de obter mojibake. Também há substituição mágica no Windows: é surpreendentemente difícil canalizar dados de um processo para outro sem modificações, por exemplodir
:\xb6
->\x14
(o exemplo no final da minha resposta)Defina universal_newlines como True, ou seja,
fonte
text=True
vez deuniversal_newlines=True
.Enquanto a resposta de @Aaron Maenpaa simplesmente funciona, um usuário perguntou recentemente :
Você pode usar:
decode()
tem um argumento padrão :fonte
.decode()
que usa'utf-8'
pode falhar (a saída do comando pode usar uma codificação de caracteres diferente ou até retornar uma sequência de bytes não codificável). Embora se a entrada for ascii (um subconjunto de utf-8),.decode()
funcionará.Para interpretar uma sequência de bytes como um texto, é necessário conhecer a codificação de caracteres correspondente:
Exemplo:
ls
O comando pode produzir uma saída que não pode ser interpretada como texto. Os nomes de arquivo no Unix podem ter qualquer sequência de bytes, exceto barrab'/'
e zerob'\0'
:Tentando decodificar essa sopa de bytes usando a codificação utf-8 aumenta
UnicodeDecodeError
.Pode ser pior. A decodificação pode falhar silenciosamente e produzir mojibake se você usar uma codificação incompatível incorreta:
Os dados estão corrompidos, mas seu programa permanece inconsciente de que ocorreu uma falha.
Em geral, qual codificação de caracteres usar não é incorporada na própria sequência de bytes. Você precisa comunicar essas informações fora da banda. Alguns resultados são mais prováveis que outros e, portanto
chardet
, existe um módulo que pode adivinhar a codificação de caracteres. Um único script Python pode usar várias codificações de caracteres em locais diferentes.ls
A saída pode ser convertida em uma string Python usando aos.fsdecode()
função que é bem-sucedida mesmo para nomes de arquivos não codificáveis (usasys.getfilesystemencoding()
esurrogateescape
manipulador de erros no Unix):Para obter os bytes originais, você pode usar
os.fsencode()
.Se você passar
universal_newlines=True
parâmetro, em seguida,subprocess
usalocale.getpreferredencoding(False)
para decodificar bytes por exemplo, pode sercp1252
no Windows.Para decodificar o fluxo de bytes em tempo real,
io.TextIOWrapper()
pode ser usado: exemplo .Comandos diferentes podem usar codificações de caracteres diferentes para sua saída, por exemplo,
dir
o comando interno (cmd
) pode usar o cp437. Para decodificar sua saída, você pode transmitir a codificação explicitamente (Python 3.6+):Os nomes dos arquivos podem diferir de
os.listdir()
(que usa a API Unicode do Windows), por exemplo,'\xb6'
podem ser substituídos'\x14'
pelos mapas de codec cp437 do Pythonb'\x14'
para controlar o caractere U + 0014 em vez de U + 00B6 (¶). Para dar suporte a nomes de arquivos com caracteres Unicode arbitrários, consulte Decodificar a saída do PowerShell que possivelmente contém caracteres Unicode não ASCII em uma sequência Pythonfonte
Como essa pergunta está realmente perguntando sobre a
subprocess
saída, você tem uma abordagem mais direta disponível, poisPopen
aceita uma palavra-chave de codificação (no Python 3.6+):A resposta geral para outros usuários é decodificar bytes para texto:
Sem argumento,
sys.getdefaultencoding()
será usado. Se seus dados não estiveremsys.getdefaultencoding()
, você deve especificar a codificação explicitamente nadecode
chamada:fonte
text=True
decodificar stdin, stdout e stderr usando a codificação fornecida (se configurada) ou o padrão do sistema.Popen(['ls', '-l'], stdout=PIPE, text=True)
.ls
saída usando autf-8
codificação pode falhar (veja o exemplo na minha resposta de 2016 ).encoding
parâmetro for fornecido, otext
parâmetro será ignorado.Se você deve obter o seguinte, tente
decode()
:Você também pode especificar o tipo de codificação diretamente em uma conversão:
fonte
Ao trabalhar com dados de sistemas Windows (com
\r\n
terminações de linha), minha resposta éPor quê? Tente isso com uma entrada multilinha:
Todas as terminações de sua linha serão dobradas (para
\r\r\n
), resultando em linhas vazias extras. As funções de leitura de texto do Python normalmente normalizam as terminações de linha, para que as strings sejam usadas apenas\n
. Se você receber dados binários de um sistema Windows, o Python não terá chance de fazer isso. Portanto,irá replicar seu arquivo original.
fonte
.replace("\r\n", "\n")
adição por tanto tempo. Esta é a resposta se você deseja renderizar HTML corretamente.Eu criei uma função para limpar uma lista
fonte
.strip
,.replace
,.encode
chamadas, etc em uma compreensão da lista e apenas iterar sobre a lista uma vez, em vez de iteração mais de cinco vezes.Para Python 3, essa é uma abordagem muito mais segura e Python para converter de
byte
parastring
:Resultado:
fonte
byte_to_str
", o que implica que ele retornará um str, mas somente imprime o valor convertido e uma mensagem de erro se falhar (mas não gera uma exceção). Essa abordagem também não é sintônica e ofusca abytes.decode
solução que você forneceu.From sys - parâmetros e funções específicos do sistema :
Para gravar ou ler dados binários de / para os fluxos padrão, use o buffer binário subjacente. Por exemplo, para escrever bytes em stdout, use
sys.stdout.buffer.write(b'abc')
.fonte
bytes
.fonte
Para o seu caso específico de "executar um comando shell e obter sua saída como texto em vez de bytes", no Python 3.7, você deve usar
subprocess.run
e passartext=True
(alémcapture_output=True
de capturar a saída)text
costumava ser chamadouniversal_newlines
e foi alterado (bem, com alias) no Python 3.7. Se você deseja suportar versões do Python anteriores à 3.7, passe emuniversal_newlines=True
vez detext=True
fonte
Se você deseja converter bytes, não apenas a string convertida em bytes:
Isso não é muito eficiente, no entanto. Ele transformará uma imagem de 2 MB em 9 MB.
fonte
tente isso
fonte