[python] Konvertieren von Bytes in eine Zeichenfolge?


Answers

Ich denke, dieser Weg ist einfach:

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

Ich verwende diesen Code, um die Standardausgabe von einem externen Programm zu erhalten:

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

Die Methode communicate () gibt ein Array von Bytes zurück:

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

Ich möchte jedoch mit der Ausgabe als normale Python-Zeichenfolge arbeiten. Damit ich es so ausdrucken kann:

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

Ich dachte, das ist, was die binascii.b2a_qp() -Methode ist, aber als ich es versuchte, habe ich wieder das gleiche Byte-Array:

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

Weiß jemand, wie man den Byte-Wert zurück in einen String konvertiert? Ich meine, benutze die "Batterien" anstatt es manuell zu machen. Und ich möchte, dass es mit Python 3 in Ordnung ist.




Wenn Sie die Codierung nicht kennen, dann lesen Sie die cp437 in die Zeichenfolge in Python 3 und Python 2 kompatible Weise, verwenden Sie alte MS-DOS- cp437 Codierung:

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

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

Da die Codierung unbekannt ist, erwarten Sie, dass nicht-englische Symbole in Zeichen von cp437 (englische Zeichen werden nicht übersetzt, da sie in den meisten cp437 Kodierungen und UTF-8 übereinstimmen).

Das Dekodieren von willkürlichen Binäreingaben in UTF-8 ist unsicher, weil Sie Folgendes bekommen können:

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

Das gleiche gilt für latin-1 , das für Python 2 sehr beliebt war (Default?). Siehe die fehlenden Punkte im Codepage Layout - hier verschluckt sich Python mit der berüchtigten ordinal not in range .

UPDATE 20150604 : Es gibt Gerüchte, dass Python 3 surrogateescape Fehler-Strategie für die Codierung von Zeug in Binärdaten ohne Datenverlust und Abstürze, aber es benötigt Umwandlungstests [binary] -> [str] -> [binary] , um Leistung und Zuverlässigkeit zu überprüfen.

UPDATE 20170116 : Dank Kommentar von Nearoo - es gibt auch eine Möglichkeit, alle unbekannten Bytes mit dem backslashreplace Error-Handler zu reduzieren. Das funktioniert nur für Python 3, daher erhalten Sie auch bei dieser Problemumgehung immer noch inkonsistente Ausgaben von verschiedenen Python-Versionen:

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

Weitere Informationen finden Sie unter https://docs.python.org/3/howto/unicode.html#python-s-unicode-support .

UPDATE 20170119 : Ich habe beschlossen, Slash-Escaping-Dekodierung zu implementieren, die sowohl für Python 2 als auch für Python 3 funktioniert. Es sollte langsamer sein als die cp437 Lösung, aber es sollte identische Ergebnisse für jede Python-Version ergeben.

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



Während die Antwort von @Aaron Maenpaa einfach funktioniert, hat kürzlich ein Benutzer gefragt

Gibt es einen einfacheren Weg? 'fhand.read () .decodieren ("ASCII")' [...] Es ist so lang!

Sie können verwenden

command_stdout.decode()

decode() hat ein Standardargument

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




Ich habe eine Funktion zum Säubern einer Liste gemacht

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



Für Python 3 ist dies ein viel sicherer und pythonischer Ansatz, um von byte zu string zu konvertieren:

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

Ausgabe:

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



In Python 3 können Sie direkt verwenden:

b'hello'.decode()

was entspricht

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

Hier ist die Standardcodierung "utf-8", oder Sie können es überprüfen durch:

>> import sys
>> sys.getdefaultencoding()



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

Verwenden Sie den zugrunde liegenden Binärpuffer, um Binärdaten von / zu den Standardströmen zu schreiben oder zu lesen. Um beispielsweise Bytes in stdout zu schreiben, verwenden Sie sys.stdout.buffer.write (b'abc ').




Related