python python3 Converter bytes em uma string?




python transform byte to string (13)

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

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

Você também pode especificar o tipo de codificação diretamente em um modelo:

>>> my_byte_str
b'Hello World'

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

Eu estou usando este 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 comunic () 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, gostaria de trabalhar com a saída como uma string normal do Python. Para que eu pudesse imprimir 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 acho que é para isso que binascii.b2a_qp() o método binascii.b2a_qp() , mas quando eu tentei obtive o mesmo array 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 de bytes de volta para string? Quero dizer, usando as "baterias" em vez de fazê-lo manualmente. E eu gostaria que ficasse bem com o Python 3.


Você precisa decodificar a string de bytes e transformá-la em uma string de caracteres (unicode).

b'hello'.decode(encoding)

ou

str(b'hello', encoding)

Ao trabalhar com dados de sistemas Windows (com \r\n finais de linha), minha resposta é

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

Por quê? Tente isso com um Input.txt de múltiplas linhas:

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

Todos os finais de linha serão duplicados (para \r\r\n ), levando a linhas vazias extras. As funções de leitura de texto do Python normalmente normalizam os finais de linha, de forma que as strings usam apenas \n . Se você receber dados binários de um sistema Windows, o Python não terá chance de fazer isso. Portanto,

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

replicará seu arquivo original.


Para o Python 3, essa é uma abordagem Python muito mais segura para 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')

Saída:

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ê não souber a codificação, então, para ler a entrada binária em string no modo compatível com Python 3 e Python 2, use a antiga codificação cp437 MS-DOS:

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

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

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 eles correspondem na maioria das codificações de byte único e UTF-8).

A decodificação da entrada binária arbitrária para UTF-8 não é segura, porque você pode obter isto:

>>> 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 ao latin-1 , que era popular (padrão?) Para o Python 2. Veja os pontos que faltam no Layout da Página de Códigos - é onde o Python engasga com o ordinal not in range infame que ordinal not in range .

ATUALIZAÇÃO 20150604 : Há rumores de que o Python 3 tem uma estratégia de erro surrogateescape para codificar coisas em dados binários sem perda de dados e travamentos, mas precisa de testes de conversão [binary] -> [str] -> [binary] para validar tanto o desempenho quanto a confiabilidade.

ATUALIZAÇÃO 20170116 : Graças ao comentário de Nearoo - há também a possibilidade de escapar de todos os bytes desconhecidos com o manipulador de erro de backslashreplace . Isso funciona apenas para o Python 3, portanto, mesmo com essa solução alternativa, você ainda obterá resultados 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#python-s-unicode-support para obter detalhes.

ATUALIZAÇÃO 20170119 : Eu decidi implementar o decodificador de escape de barra que funciona tanto para o Python 2 quanto para o Python 3. Deve ser mais lento que a solução cp437 , mas deve produzir resultados idênticos em todas as versões do 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'))

Definir universal_newlines para True, ou seja

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

Eu acho que isso é fácil:

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

Enquanto a resposta de @Aaron Maenpaa simplesmente funciona, um usuário perguntou recentemente

Existe alguma maneira mais simples? 'fhand.read (). decode ("ASCII")' [...] É tão longo!

Você pode usar

command_stdout.decode()

decode() tem um argumento padrão

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


Como essa pergunta está realmente perguntando sobre a saída do subprocess , você tem uma abordagem mais direta disponível, pois o Popen aceita uma palavra-chave de encoding (no 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 é decodificar bytes em texto:

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

Sem argumento, sys.getdefaultencoding() será usado. Se seus dados não são sys.getdefaultencoding() , você deve especificar a codificação explicitamente na chamada de decode :

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

Eu acho que o que você realmente quer é isso:

>>> 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 correta, exceto que você precisa saber QUAL codificação usar. E eu acredito que o Windows usa 'windows-1252'. Só terá importância se você tiver alguns caracteres incomuns (não-ascii) em seu conteúdo, mas isso fará diferença.

A propósito, o fato de que isso importa é o motivo pelo qual o Python passou a usar dois tipos diferentes de dados binários e de texto: ele não pode converter magicamente entre eles porque não sabe a codificação, a menos que você o informe! A única maneira que você sabe é ler a documentação do Windows (ou lê-lo aqui).


Você precisa decodificar o objeto de bytes 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'

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

b'hello'.decode()

que é equivalente a

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

Por outro lado, no Python 2 , a codificação é padronizada para a codificação de string padrão. Assim, você deve usar:

b'hello'.decode(encoding)

onde a encoding é a codificação desejada.

Nota: o suporte para argumentos de palavras-chave foi adicionado no Python 2.7.





python-3.x