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.

War es hilfreich?

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

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

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top