Konvertieren Bytes in einen String?
-
03-07-2019 - |
Frage
Ich verwende diesen Code Standardausgabe von einem externen Programm zu erhalten:
>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
Die kommunizieren () Methode ein Array von Bytes zurückgibt:
>>> 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'
Aber ich mag mit dem Ausgang als normale Python-String arbeiten. Damit ich es so drucken können:
>>> 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 der binascii.b2a_qp () Methode ist für, aber wenn ich es versuche, bekam ich den gleichen Byte-Array wieder:
>>> 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 der Bytes-Wert zu konvertieren zurück zu String? Ich meine, mit den „Batterien“, anstatt sie manuell zu tun. Und ich mag es mit Python 3 in Ordnung sein.
Lösung
Sie müssen die Bytes Objekt entschlüsseln eine Zeichenfolge erzeugen:
>>> 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'
Andere Tipps
Ich denke, diese Art und Weise ist einfach:
bytes_data = [112, 52, 52]
"".join(map(chr, bytes_data))
>> p44
Sie müssen die Byte-Zeichenfolge entschlüsseln und schalten Sie ihn in einem Zeichen (Unicode) Zeichenfolge.
Auf Python 2
encoding = 'utf-8'
b'hello'.decode(encoding)
Auf Python 3
encoding = 'utf-8'
str(b'hello', encoding)
Wenn Sie nicht die Kodierung kennen, dann Binäreingang in String in Python 3 und Python 2-kompatible Weise verwendet altes 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 Codierung nicht bekannt ist, erwarten nicht-englischen Zeichen zu Zeichen von cp437
zu übersetzen (Englisch Zeichen werden nicht übersetzt, weil sie in den meisten Single-Byte-Codierungen und UTF-8 übereinstimmen).
Die Decodierung beliebige binäre Eingabe in UTF-8 ist unsicher, weil Sie dies 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
, was populär war (default?) Für Python 2. die fehlenden Punkte Siehe in Codepage-Layout -. es ist, wo Python mit berüchtigten ordinal not in range
Drosseln
UPDATE 20150604 . Es gibt Gerüchte, dass Python 3 Sachen Fehler-Strategie für die Codierung in binäre Daten ohne Datenverlust und Abstürze surrogateescape
hat, aber es muss Umwandlung Tests [binary] -> [str] -> [binary]
sowohl Leistung und Zuverlässigkeit bestätigen
UPDATE 20170116 : Danke von Nearoo Kommentar - es gibt auch eine Möglichkeit, all unbekanntes Bytes mit backslashreplace
Fehlerbehandlung zu entkommen zu zerschneiden. Das funktioniert nur für Python 3, so dass auch mit dieser Problemumgehung werden Sie noch inkonsistent Ausgabe 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'))
Siehe https: //docs.python. org / 3 / Howto / unicode.html # python-s-Unicode-Unterstützung .
UPDATE 20170119 : Ich beschloss, slash Flucht dekodieren zu implementieren, die 3. für beide Python 2 und Python funktioniert es langsamer, dass cp437
Lösung sein sollte, aber es sollte identische Ergebnisse erzeugen 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'))
In Python 3 ist die Standard-Kodierung "utf-8"
, so können Sie verwenden, um direkt:
b'hello'.decode()
das ist äquivalent zu
b'hello'.decode(encoding="utf-8")
Auf der anderen Seite, in Python 2 , Codierung standardmäßig auf die Standard-String-Codierung. Daher sollten Sie verwenden:
b'hello'.decode(encoding)
wo encoding
ist die Codierung Sie wollen.
Hinweis: Unterstützung für die Keyword-Argumente wurde in Python 2.7.
hinzugefügtIch denke, was Sie eigentlich wollen, ist dies:
>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
>>> command_text = command_stdout.decode(encoding='windows-1252')
Aaron Antwort richtig war, mit der Ausnahme, dass Sie wissen müssen, welche Kodierung zu verwenden. Und ich glaube, dass Windows ‚windows-1252‘ verwendet. Es wird nur aus, wenn Sie einige ungewöhnliche (non-ascii) Zeichen in Ihrem Inhalt haben, aber dann wird es einen Unterschied machen.
Durch die Art und Weise, die Tatsache, dass es keine Rolle spielt ist der Grund, dass Python mit zwei verschiedenen Typen für binäre und Textdaten verschoben: es kann nicht auf magische Weise zwischen ihnen umwandeln, weil es nicht die Kodierung nicht wissen, wenn Sie es sagen ! Der einzige Weg, Sie wissen würden, ist die Windows-Dokumentation zu lesen (oder hier lesen).
Set universal_newlines auf True, d.
command_stdout = Popen(['ls', '-l'], stdout=PIPE, universal_newlines=True).communicate()[0]
Während @Aaron Maenpaa Antwort nur funktioniert, ein Benutzer vor kurzem gefragt :
Gibt es eine einfachere Art und Weise? 'Fhand.read (). Entschlüsseln ( "ASCII")' [...] Es ist so lang!
Sie können mit:
command_stdout.decode()
decode()
hat ein Standardargument :
codecs.decode(obj, encoding='utf-8', errors='strict')
Um eine Byte-Sequenz als Text zu interpretieren, müssen Sie wissen, die entsprechende Zeichencodierung:
unicode_text = bytestring.decode(character_encoding)
Beispiel:
>>> b'\xc2\xb5'.decode('utf-8')
'µ'
ls
Befehl kann Ausgabe erzeugen, die nicht als Text interpretiert werden kann. Die Dateinamen
auf Unix kann eine beliebige Folge von Bytes mit Ausnahme slash b'/'
und Null sein
b'\0'
:
>>> open(bytes(range(0x100)).translate(None, b'\0/'), 'w').close()
Der Versuch, solche Byte-Suppe mit UTF-8-Codierung erhöht UnicodeDecodeError
zu dekodieren.
Es kann schlimmer sein. Die Decodierung kann geräuschlos und erzeugen nicht Mojibake wenn Sie eine falsche inkompatibel Codierung verwenden:
>>> '—'.encode('utf-8').decode('cp1252')
'—'
Die Daten werden beschädigt, aber Ihr Programm bleibt nicht bewusst, dass ein Ausfall aufgetreten ist.
Im Allgemeinen welche Zeichencodierung zu verwenden ist nicht in der Byte-Sequenz selbst eingebettet. Sie haben diese Informationen Out-of-Band zu kommunizieren. Einige Ergebnisse sind eher als andere und deshalb chardet
Modul besteht, dass können erraten die Zeichenkodierung. Ein einzelner Python-Skript mehr Zeichencodierungen an verschiedenen Orten verwenden.
ls
Ausgang kann auf einen Python-String mit os.fsdecode()
umgewandelt werden
Funktion, die auch für undecodierbare gelingt
Dateinamen (es verwendet
sys.getfilesystemencoding()
und surrogateescape
Fehlerbehandlung auf
Unix):
import os
import subprocess
output = os.fsdecode(subprocess.check_output('ls'))
Um das ursprüngliche Bytes zu erhalten, könnten Sie os.fsencode()
verwenden.
Wenn Sie passieren universal_newlines=True
Parameter dann subprocess
Anwendungen
locale.getpreferredencoding(False)
zu dekodieren Bytes z.B. kann es sein,
cp1252
unter Windows.
Um die Byte-Stream on-the-fly zu dekodieren,
io.TextIOWrapper()
könnte verwendet werden. Beispiel
Verschiedene Befehle können unterschiedliche Zeichencodierungen verwenden für ihre
Ausgabe z.B. dir
internen Befehl (cmd
) CP437 verwenden. Zur Decodierung seines
Ausgabe, können Sie die Codierung explizit (Python 3.6 +) übergeben:
output = subprocess.check_output('dir', shell=True, encoding='cp437')
Die Dateinamen von os.listdir()
abweichen können (die Windows verwendet
Unicode API) z.B. '\xb6'
mit '\x14'
-Python ersetzt werden
CP437 codec Karten b'\x14'
Zeichen U steuern + 0014 anstelle von
U + 00B6 (¶). Um Dateinamen mit beliebigen Unicode-Zeichen finden Sie unter Decode poweshell Ausgang möglicherweise Nicht-ASCII-Unicode-Zeichen in einen Python-String mit
Da diese Frage tatsächlich fragt nach subprocess
Ausgabe, haben Sie einen direkteren Ansatz zur Verfügung, da Popen
akzeptieren ein Codierung Stichwort (in 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
Die allgemeine Antwort für andere Benutzer zu dekodieren Bytes Text:
>>> b'abcde'.decode()
'abcde'
Ohne Argument sys.getdefaultencoding()
verwendet. Wenn Ihre Daten nicht sys.getdefaultencoding()
, dann müssen Sie die Codierung angeben explizit in der decode
Aufruf:
>>> b'caf\xe9'.decode('cp1250')
'café'
Wenn Sie die folgenden, indem Sie versuchen decode()
bekommen sollte:
Attribute: 'str' Objekt hat kein Attribut 'decode'
Sie können auch den Codierungstyp gerade in einer Besetzung angeben:
>>> my_byte_str
b'Hello World'
>>> str(my_byte_str, 'utf-8')
'Hello World'
Wenn Sie mit Daten aus Windows-Systemen (mit \r\n
Zeilenenden) arbeitet, ist meine Antwort
String = Bytes.decode("utf-8").replace("\r\n", "\n")
Warum? Versuchen Sie dies mit einem mehrzeiligen Eingabe.txt:
Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8")
open("Output.txt", "w").write(String)
Ihr alle Zeilenenden wird verdoppelt (auf \r\r\n
), was zu zusätzlichen Leerzeilen. Pythons Text-Lesefunktionen normalisieren normalerweise Zeilenende, so dass Strings nur \n
verwenden. Wenn Sie binäre Daten von einem Windows-System zu erhalten, Python hat keine Chance, das zu tun. So
Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8").replace("\r\n", "\n")
open("Output.txt", "w").write(String)
Ihre ursprüngliche Datei repliziert werden.
Ich habe eine Funktion, um eine Liste zu reinigen
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, das ist eine viel sicherere und Pythonic Ansatz von byte
zu konvertieren 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')
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
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))
Wenn Sie irgendwelche Bytes konvertieren wollen, nicht nur String in Bytes umgewandelt:
with open("bytesfile", "rb") as infile:
str = base64.b85encode(imageFile.read())
with open("bytesfile", "rb") as infile:
str2 = json.dumps(list(infile.read()))
Das ist nicht sehr effizient, aber. Es wird ein 2 mb Bild in 9 mb drehen.
http://docs.python.org/3/library/sys. html ,
So schreiben oder Binärdaten gelesen von / zu den Standard-Streams, die zugrunde liegenden Binärpuffer verwenden. Zum Beispiel schreibt Bytes auf stdout, verwenden sys.stdout.buffer.write(b'abc')
.