Konvertieren Sie Bytes in einen String in Python 3
Lesezeit: 7 Minuten
Tomas Sedovic
Ich habe die Standardausgabe eines externen Programms in a erfasst bytes Objekt:
>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
>>>
>>> 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 das in einen normalen Python-String umwandeln, damit ich ihn wie folgt 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
Wie konvertiere ich die bytes Einspruch gegen a str mit Python 3?
Siehe Beste Möglichkeit zum Konvertieren von Zeichenfolgen in Bytes in Python 3? für den umgekehrten Fall.
warum nicht str(text_bytes) arbeiten? Das kommt mir bizarr vor.
– Charlie Parker
14. März 2019 um 22:25 Uhr
@CharlieParker Weil str(text_bytes) Die Codierung kann nicht angegeben werden. Abhängig davon, was in text_bytes steht, text_bytes.decode('cp1250)` könnte zu einer ganz anderen Zeichenfolge führen als text_bytes.decode('utf-8').
– Craig Anderson
31. März 2019 um 17:32 Uhr
So str Funktion wird nicht mehr in einen echten String konvertiert. Aus irgendeinem Grund MUSS man explizit eine Codierung sagen. Ich bin zu faul, um zu lesen, warum. Konvertieren Sie es einfach in utf-8 und sehen Sie, ob Ihr Code funktioniert. z.B var = var.decode('utf-8')
– Charlie Parker
22. April 2019 um 23:32 Uhr
@CraigAnderson: unicode_text = str(bytestring, character_encoding) Funktioniert jedoch wie erwartet unter Python 3 unicode_text = bytestring.decode(character_encoding) ist vorzuziehen, um Verwechslungen mit just zu vermeiden str(bytes_obj) das erzeugt eine Textdarstellung für bytes_obj Anstatt es in Text zu dekodieren: str(b'\xb6', 'cp1252') == b'\xb6'.decode('cp1252') == '¶' Und str(b'\xb6') == "b'\\xb6'" == repr(b'\xb6') != '¶'
– jfs
12. April 2020 um 5:11 Uhr
Sie können auch bestehen text=True Zu subprocess.run() oder .Popen() und dann erhalten Sie eine Zeichenfolge zurück, ohne dass Bytes konvertiert werden müssen. Oder angeben encoding="utf-8" zu einer der beiden Funktionen.
Das obige Beispiel geht davon aus dass die bytes Das Objekt ist in UTF-8, da es sich um eine gängige Kodierung handelt. Sie sollten jedoch die Codierung verwenden, in der sich Ihre Daten tatsächlich befinden!
Ja, aber da dies die Ausgabe eines Windows-Befehls ist, sollte stattdessen nicht „.decode(‘windows-1252’)“ verwendet werden?
– mcherm
18. Juli 2011 um 19:48
Benutzen "windows-1252" auch nicht zuverlässig ist (z. B. für andere Sprachversionen von Windows), wäre es nicht das Beste, es zu verwenden sys.stdout.encoding?
– nikow
3. Januar 2012 um 15:20
Vielleicht hilft das jemandem weiter: Manchmal verwenden Sie Byte-Arrays für die TCP-Kommunikation. Wenn Sie ein Byte-Array in eine Zeichenfolge umwandeln möchten, indem Sie nachgestellte „\x00“-Zeichen abschneiden, reicht die folgende Antwort nicht aus. Verwenden Sie dann b’example\x00\x00′.decode(‘utf-8’).strip(‘\x00’).
@leetNightshade: Dennoch ist es furchtbar ineffizient. Wenn Sie ein Byte-Array haben, müssen Sie es nur dekodieren.
– Martijn Pieters ♦
1. September 2014 um 16:25
@Sasszem: Diese Methode ist eine perverse Art auszudrücken: a.decode('latin-1') Wo a = bytearray([112, 52, 52]) („Es gibt keinen Klartext“. Wenn Sie es geschafft haben, Bytes in eine Textzeichenfolge umzuwandeln, haben Sie eine Codierung verwendet –latin-1 in diesem Fall)
– jfs
16. November 2016 um 3:16
@leetNightshade: Der Vollständigkeit halber: bytes(list_of_integers).decode('ascii') ist etwa 1/3 schneller als ''.join(map(chr, list_of_integers)) auf Python 3.6.
– Martijn Pieters ♦
3. Juli 2018 um 12:01 Uhr
anatoli techtonik
Wenn Sie die Codierung nicht kennen, verwenden Sie das alte MS-DOS, um binäre Eingaben auf eine mit Python 3 und Python 2 kompatible Weise in einen String einzulesen 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, müssen Sie damit rechnen, dass nicht-englische Symbole in Zeichen von übersetzt werden cp437 (Englische Zeichen werden nicht übersetzt, da sie in den meisten Einzelbyte-Kodierungen und UTF-8 übereinstimmen).
Das Dekodieren beliebiger Binäreingaben 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
Gleiches gilt für latin-1was für Python 2 beliebt war (die Standardeinstellung?). Siehe die fehlenden Punkte in Codepage-Layout – Hier erstickt Python vor Berüchtigtheit ordinal not in range.
UPDATE 20150604: Es gibt Gerüchte, dass Python 3 das hat surrogateescape Fehlerstrategie zum Codieren von Inhalten in Binärdaten ohne Datenverlust und Abstürze, aber es sind Konvertierungstests erforderlich. [binary] -> [str] -> [binary]um sowohl Leistung als auch Zuverlässigkeit zu validieren.
UPDATE 20170116: Dank des Kommentars von Nearoo gibt es auch die Möglichkeit, alle unbekannten Bytes mit einem Slash-Escape zu versehen backslashreplace Fehlerbehandler. Das funktioniert nur für Python 3, sodass Sie selbst mit dieser Problemumgehung immer noch inkonsistente Ausgaben verschiedener 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'))
UPDATE 20170119: Ich habe beschlossen, Slash-Escape-Dekodierung zu implementieren, die sowohl für Python 2 als auch für Python 3 funktioniert. Sie sollte langsamer sein als die cp437 Lösung, aber es sollte produzieren identische Ergebnisse auf jeder Python-Version.
# --- 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'))
lmiguelvargasf
In Python 3die Standardkodierung ist "utf-8"sodass Sie Folgendes direkt verwenden können:
b'hello'.decode()
was gleichbedeutend mit ist
b'hello'.decode(encoding="utf-8")
Andererseits, in Python 2Die Codierung erfolgt standardmäßig auf die Standard-String-Codierung. Daher sollten Sie Folgendes verwenden:
b'hello'.decode(encoding)
Wo encoding ist die gewünschte Codierung.
Notiz: Unterstützung für Schlüsselwortargumente wurde in Python 2.7 hinzugefügt.
Aarons Antwort war richtig, außer dass Sie es wissen müssen welche zu verwendende Kodierung. Und ich glaube, dass Windows „Windows-1252“ verwendet. Es spielt nur dann eine Rolle, wenn Ihr Inhalt ungewöhnliche Zeichen (nicht ASCII) enthält, aber dann macht es einen Unterschied.
Übrigens, die Tatsache, dass es tut Materie ist der Grund dafür, dass Python dazu übergegangen ist, zwei verschiedene Typen für Binär- und Textdaten zu verwenden: Es kann nicht auf magische Weise zwischen ihnen konvertieren, weil es die Codierung nicht kennt, es sei denn, Sie sagen es ihm! Die einzige Möglichkeit, die Sie wissen würden, besteht darin, die Windows-Dokumentation zu lesen (oder sie hier zu lesen).
Da es sich bei dieser Frage eigentlich um eine Frage handelt subprocess Ausgabe stehen Ihnen mehr direkte Ansätze zur Verfügung. Am modernsten wäre die Nutzung subprocess.check_output und vorbei text=True (Python 3.7+) zum automatischen Dekodieren von stdout unter Verwendung der Systemstandardkodierung:
text = subprocess.check_output(["ls", "-l"], text=True)
Für Python 3.6, Popen akzeptiert eine Codierung Stichwort:
>>> 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
Wenn Sie sich nicht mit der Ausgabe von Unterprozessen befassen, lautet die allgemeine Antwort auf die Frage im Titel: dekodieren Bytes zum Text:
>>> b'abcde'.decode()
'abcde'
Ohne Argument, sys.getdefaultencoding() verwendet wird. Wenn Ihre Daten nicht vorhanden sind sys.getdefaultencoding()dann müssen Sie die Kodierung explizit im angeben decode Forderung:
>>> b'caf\xe9'.decode('cp1250')
'café'
14547300cookie-checkKonvertieren Sie Bytes in einen String in Python 3yes
warum nicht
str(text_bytes)
arbeiten? Das kommt mir bizarr vor.– Charlie Parker
14. März 2019 um 22:25 Uhr
@CharlieParker Weil
str(text_bytes)
Die Codierung kann nicht angegeben werden. Abhängig davon, was in text_bytes steht,text_bytes.decode('cp1250
)` könnte zu einer ganz anderen Zeichenfolge führen alstext_bytes.decode('utf-8')
.– Craig Anderson
31. März 2019 um 17:32 Uhr
So
str
Funktion wird nicht mehr in einen echten String konvertiert. Aus irgendeinem Grund MUSS man explizit eine Codierung sagen. Ich bin zu faul, um zu lesen, warum. Konvertieren Sie es einfach inutf-8
und sehen Sie, ob Ihr Code funktioniert. z.Bvar = var.decode('utf-8')
– Charlie Parker
22. April 2019 um 23:32 Uhr
@CraigAnderson:
unicode_text = str(bytestring, character_encoding)
Funktioniert jedoch wie erwartet unter Python 3unicode_text = bytestring.decode(character_encoding)
ist vorzuziehen, um Verwechslungen mit just zu vermeidenstr(bytes_obj)
das erzeugt eine Textdarstellung fürbytes_obj
Anstatt es in Text zu dekodieren:str(b'\xb6', 'cp1252') == b'\xb6'.decode('cp1252') == '¶'
Undstr(b'\xb6') == "b'\\xb6'" == repr(b'\xb6') != '¶'
– jfs
12. April 2020 um 5:11 Uhr
Sie können auch bestehen
text=True
Zusubprocess.run()
oder.Popen()
und dann erhalten Sie eine Zeichenfolge zurück, ohne dass Bytes konvertiert werden müssen. Oder angebenencoding="utf-8"
zu einer der beiden Funktionen.– David Gilbertson
13. September 2022 um 5:46 Uhr