it-swarm.com.de

Bytes in einen String konvertieren?

Ich verwende diesen Code, um die Standardausgabe eines externen Programms zu erhalten:

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

Die communic () -Methode 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 würde jedoch gerne mit der Ausgabe als normaler Python-String 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, dafür ist die binascii.b2a_qp () -Methode gedacht, aber als ich es ausprobierte, bekam 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 Bytewert zurück in Zeichenkette umwandelt? Ich meine, mit den "Batterien", anstatt es manuell zu tun. Und ich möchte, dass es mit Python 3 in Ordnung ist.

1818
Tomas Sedovic

Sie müssen das bytes-Objekt dekodieren, um eine Zeichenfolge zu erstellen:

>>> 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'
2962
Aaron Maenpaa

Sie müssen die Byte-Zeichenfolge dekodieren und in eine Zeichenfolge (Unicode) umwandeln.

Am Python 2

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

oder

unicode('hello', encoding)

Am Python 3

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

oder

str(b'hello', encoding)
163
dF.

Ich denke, dieser Weg ist einfach:

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

Wenn Sie die Codierung nicht kennen, können Sie Binäreingaben in Zeichenfolgen in Python 3 und Python 2 kompatibler Weise lesen, indem Sie das alte MS-DOS cp437 verwenden Codierung:

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

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

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

Das Dekodieren einer beliebigen Binäreingabe in UTF-8 ist unsicher, da Sie möglicherweise Folgendes erhalten:

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

Dasselbe gilt für latin-1, das für Python beliebt war (Standardeinstellung?). 2. Siehe die fehlenden Punkte in Codepage-Layout - hier ist Python Drosseln mit berüchtigten ordinal not in range.

UPDATE 20150604 : Es gibt Gerüchte, dass Python 3 eine surrogateescape Fehlerstrategie für das Codieren von Inhalten in Binärdaten ohne Datenverlust hat und stürzt ab, es sind jedoch Konvertierungstests [binary] -> [str] -> [binary] erforderlich, um sowohl die Leistung als auch die Zuverlässigkeit zu überprüfen.

UPDATE 20170116 : Dank des Kommentars von Nearoo gibt es auch die Möglichkeit, mit dem backslashreplace Fehlerhandler alle unbekannten Bytes zu entfernen. Das funktioniert nur für Python 3, sodass Sie auch mit dieser Problemumgehung immer noch inkonsistente Ausgaben von verschiedenen Python Versionen erhalten:

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 mich für die Implementierung von Schrägstrich-Escape-Dekodierung entschieden, die sowohl für Python 2 als auch Python 3 funktioniert. Es sollte langsamer sein als die cp437 -Lösung, aber es sollte bei jeder Python -Version zu identischen Ergebnissen führen.

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

In Python ist die Standardkodierung "utf-8", sodass Sie direkt Folgendes verwenden können:

b'hello'.decode()

das ist äquivalent zu

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

Andererseits wird bei in Python 2 standardmäßig die Standardzeichenfolgencodierung verwendet. Daher sollten Sie verwenden:

b'hello'.decode(encoding)

wobei encoding die gewünschte Codierung ist.

Hinweis: Unterstützung für Schlüsselwortargumente wurde in Python 2.7 hinzugefügt.

67
lmiguelvargasf

Ich denke, was Sie eigentlich wollen, ist Folgendes:

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

Aarons Antwort war korrekt, außer dass Sie wissen müssen, WELCHE Codierung verwendet werden soll. Und ich glaube, dass Windows "Windows-1252" verwendet. Es ist nur von Bedeutung, wenn Sie einige ungewöhnliche (Nicht-ASCII-) Zeichen in Ihrem Inhalt haben, aber dann wird es einen Unterschied machen.

Übrigens ist die Tatsache, dass es wichtig ist, der Grund, dass Python zwei verschiedene Typen für Binär- und Textdaten verwendet: Es kann nicht magisch zwischen ihnen konvertiert werden, da es die Codierung nicht kennt, es sei denn du sagst es! Sie können die Windows-Dokumentation nur lesen (oder hier lesen).

38
mcherm

Setzen Sie universal_newlines auf True, d. H.

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

Während @ Aaron Maenpaas Antwort gerade funktioniert, fragte ein Benutzer kürzlich :

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

Sie können verwenden:

command_stdout.decode()

decode() hat ein Standardargument :

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

19
serv-inc

Da sich diese Frage tatsächlich mit der Ausgabe von subprocess befasst, haben Sie eine direktere Möglichkeit, da Popen ein encoding Schlüsselwort (in Pythonakzeptiert. _ 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

Die allgemeine Antwort für andere Benutzer ist, Bytes in Text zu dekodieren:

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

Ohne Argument wird sys.getdefaultencoding() verwendet. Wenn Ihre Daten nicht sys.getdefaultencoding() sind, müssen Sie die Codierung im Aufruf decode explizit angeben:

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

Um eine Bytefolge als Text zu interpretieren, müssen Sie die entsprechende Zeichenkodierung kennen:

unicode_text = bytestring.decode(character_encoding)

Beispiel:

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

Der Befehl ls kann eine Ausgabe erzeugen, die nicht als Text interpretiert werden kann. Dateinamen unter Unix können eine beliebige Folge von Bytes sein, mit Ausnahme von Schrägstrich b'/' und Null b'\0':

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

Der Versuch, eine solche Bytesuppe mit der utf-8-Codierung zu decodieren, löst UnicodeDecodeError aus.

Es kann schlimmer sein. Die Dekodierung kann im Hintergrund fehlschlagen und mojibake erzeugen, wenn Sie eine falsche inkompatible Kodierung verwenden:

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

Die Daten sind beschädigt, aber Ihr Programm weiß nicht, dass ein Fehler aufgetreten ist.

Im Allgemeinen ist die zu verwendende Zeichencodierung nicht in der Bytefolge selbst eingebettet. Sie müssen diese Informationen außerhalb des Bandes kommunizieren. Einige Ergebnisse sind wahrscheinlicher als andere und daher gibt es ein chardet -Modul, das die Zeichencodierung erraten kann. Ein einzelnes Python Skript kann mehrere Zeichenkodierungen an verschiedenen Stellen verwenden.


Die Ausgabe von ls kann mit der Funktion os.fsdecode() in eine Python Zeichenfolge konvertiert werden, die auch für nicht decodierbare Dateinamen (verwendet die Fehlerbehandlungsroutine sys.getfilesystemencoding() und surrogateescape unter Unix) erfolgreich ist. :

import os
import subprocess

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

Um die ursprünglichen Bytes zu erhalten, können Sie os.fsencode() verwenden.

Wenn Sie den Parameter universal_newlines=True übergeben, verwendet subprocesslocale.getpreferredencoding(False), um Bytes zu decodieren. Unter Windows kann es sich beispielsweise um cp1252 handeln.

Um den Bytestrom im laufenden Betrieb zu dekodieren, könnte io.TextIOWrapper() verwendet werden: Beispiel .

Unterschiedliche Befehle können unterschiedliche Zeichencodierungen für ihre Ausgabe verwenden, z. B. kann der interne Befehl dir (cmd) cp437 verwenden. Um die Ausgabe zu dekodieren, können Sie die Kodierung explizit übergeben (Python 3.6+):

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

Die Dateinamen können von os.listdir() (die die Windows Unicode-API verwendet) abweichen, z. B. kann '\xb6' durch '\x14' ersetzt werden - Pythons cp437-Codec ordnet b'\x14' zu, um das Zeichen U + 0014 anstelle von U + 00B6 (¶) zu steuern. Informationen zur Unterstützung von Dateinamen mit beliebigen Unicode-Zeichen finden Sie unter Dekodieren von Poweshell-Ausgaben, die möglicherweise nicht-ASCII-Unicode-Zeichen enthalten, in eine python-Zeichenfolge

13
jfs

Wenn Sie das Folgende erhalten sollten, indem Sie decode() versuchen:

AttributeError: Objekt 'str' hat kein Attribut 'decode'

Sie können den Codierungstyp auch direkt in einer Besetzung angeben:

>>> my_byte_str
b'Hello World'

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

Bei der Arbeit mit Daten von Windows-Systemen (mit \r\n Zeilenenden) lautet meine Antwort

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

Warum? Versuchen Sie dies mit einer mehrzeiligen Input.txt:

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

Alle Ihre Zeilenenden werden verdoppelt (zu \r\r\n), was zu zusätzlichen Leerzeilen führt. Pythons Textlesefunktionen normalisieren normalerweise Zeilenenden, sodass Zeichenfolgen nur \n verwenden. Wenn Sie Binärdaten von einem Windows-System erhalten, hat Python keine Chance dazu. Somit,

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

repliziert Ihre Originaldatei.

5
bers

Ich habe eine Funktion erstellt, um eine Liste zu bereinigen

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

Für Python 3 ist dies ein viel sichererer und pythonischer Ansatz, um von byte nach 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
2
Inconnu

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

Verwenden Sie den zugrunde liegenden Binärpuffer, um Binärdaten aus/in die Standard-Streams zu schreiben oder zu lesen. Um beispielsweise Bytes in stdout zu schreiben, verwenden Sie sys.stdout.buffer.write(b'abc').

2
Zhichang Yu
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))
1
Leonardo Filipe

Wenn Sie beliebige Bytes konvertieren möchten, werden nicht nur Zeichenfolgen in Bytes konvertiert:

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

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

Dies ist jedoch nicht sehr effizient. Es wird ein 2 MB Bild in 9 MB verwandeln.

1
HCLivess

Für Ihren speziellen Fall, dass Sie "einen Shell-Befehl ausführen und dessen Ausgabe als Text anstelle von Bytes erhalten", auf Python 3.7 sollte subprocess.run verwenden und _text=True_ übergeben (sowie _capture_output=True_, um die Ausgabe zu erfassen)

_command_result = subprocess.run(["ls", "-l"], capture_output=True, text=True)
command_result.stdout  # is a `str` containing your program's stdout
_

text hieß früher _universal_newlines_ und wurde in Python 3.7 geändert. Wenn Sie Python Versionen vor 3.7 unterstützen möchten, übergeben Sie _universal_newlines=True_ anstelle von _text=True_

0
Boris