Używam tego kodu, aby uzyskać standardowe wyjście z zewnętrznego programu:

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

Metoda komunikacji () zwraca tablicę bajtów:

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

Chciałbym jednak pracować z wyjściem jako normalny ciąg Pythona. Więc mogłem go wydrukować taki:

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

Myślałem, że to właśnie binascii.b2a_QP () Metoda jest dla, ale kiedy spróbowałem, dostałem ponownie tę samą tablicę bajtową:

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

Jak konwertować wartość bajdów z powrotem do łańcucha? To znaczy, używając "baterii" zamiast go robić ręcznie. I chciałbym być OK z Pythonem 3.

3115
Tomas Sedovic 3 marzec 2009, 15:23

19 odpowiedzi

Najlepsza odpowiedź

Musisz dekodować obiekt bajtów, aby wytworzyć ciąg:

>>> 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'
4233
Aaron Maenpaa 24 lipiec 2015, 18:14

Aby interpretować sekwencję bajtową jako tekst, musisz znać odpowiednie kodowanie znaków:

unicode_text = bytestring.decode(character_encoding)

Przykład:

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

ls Polecenie może produkować produkcję, której nie można interpretować jako tekst. Nazwy plików. W UNIX może być dowolną sekwencją bajtów z wyjątkiem slash {x1}} i zero b'\0':

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

Próbując dekodować taką zupę bajtową za pomocą kodowania UTF-8 podnosi UnicodeDecodeError.

Może być gorzej. Dekodowanie może zawieść cicho i produkować mojibake Jeśli używasz niewłaściwego niezgodnego kodowania:

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

Dane są uszkodzone, ale Twój program pozostaje nieświadomy, że wystąpiła awaria.

Ogólnie rzecz biorąc, jakie kodowanie znaków do użycia nie jest osadzone w samej sekwencji bajtów. Musisz przekazać te informacje poza zespołem. Niektóre wyniki są bardziej prawdopodobne niż inne, a zatem moduł chardet istnieje, że może Zgadnij kodowanie znaków. Pojedynczy skrypt Pythona może używać wielu kodowania znaków w różnych miejscach.


ls Wyjście można przekonwertować na łańcuch Python przy użyciu os.fsdecode() Funkcja, która odnosi sukces nawet dla Niedeczowy nazwy plików (używa sys.getfilesystemencoding() i surrogateescape Handler błędu UNIX):

import os
import subprocess

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

Aby uzyskać oryginalne bajty, możesz użyć os.fsencode().

Jeśli przejdziesz universal_newlines=True parametr, a następnie subprocess używa locale.getpreferredencoding(False) Aby zdekodować bajty na e.g., może być cp1252 W systemie Windows.

Aby zdekodować strumień bajtów w locie, io.TextIOWrapper() Może być używany: Przykład.

Różne polecenia mogą korzystać z różnych kodowania znaków dla ich Wyjście E.G., polecenie wewnętrzne {x0}} ({x1}}) może używać CP437. Dekodować jego Wyjście, możesz wyraźnie przejść kodowanie (Python 3.6+):

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

Nazwy plików mogą się różnić od os.listdir() (który wykorzystuje okna Unicode API) np. {X1}} może być zastąpiony '\x14' - Pythona CP437 CODEC Maps b'\x14' do sterowania znakiem U + 0014 zamiast U + 00B6 (). Aby wspierać nazwy plików z dowolnymi znakami Unicode, zobacz Decode PowerShell Wyjście Prawdopodobnie zawierające znaki nie-ASCII Unicode w strumieniu Python

29
jfs 4 październik 2019, 20:19

Musisz dekodować ciąg bajtów i włączyć go do znaku znaków (Unicode).

Na pythonie 2.

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

Lub

unicode('hello', encoding)

Na Pythonie 3.

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

Lub

str(b'hello', encoding)
266
Peter Mortensen 28 wrzesień 2019, 10:52

Myślę, że ten sposób jest łatwy:

bytes_data = [112, 52, 52]
"".join(map(chr, bytes_data))
>> p44
204
Zohnannor 14 maj 2020, 18:31

Jeśli nie znasz kodowania, aby odczytać wejście binarne do ciągów w Python 3 i Python 2 zgodny, użyj starożytnej MS-DOS CP437 kodowanie:

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

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

Ponieważ kodowanie jest nieznane, oczekuj symboli nie-angielskich, aby przetłumaczyć na znaki {x0}} (angielskie znaki nie są tłumaczone, ponieważ pasują do większości kodowania bajtów i UTF-8).

Dekodowanie dowolnego wejścia binarnego do UTF-8 jest niebezpieczne, ponieważ możesz to uzyskać:

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

To samo dotyczy latin-1, który był popularny (domyślny?) Dla Pythona 2. Zobacz brakujące punkty w Układ CodePage - Tam, gdzie dławiki Pythona z niesławnym {X1}}.

Aktualizacja 2015064 : Istnieją pogłoski, że Python 3 ma strategię błędów surrogateescape do kodowania rzeczy do danych binarnych bez utraty danych i awarii, ale wymaga testów konwersji, [binary] -> [str] -> [binary], do Sprawdź poprawność wydajności i niezawodności.

Aktualizacja 20170116 : Dzięki komentarzu przez Wlisko - istnieje również możliwość usunięcia wszystkich nieznanych bajtów z backslashreplace Handler błędu. To działa tylko dla Pythona 3, więc nawet z tym obejściem nadal otrzymasz niespójne wyjście z różnych wersji Pythona:

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

Patrz Python's Unicode Support Szczegółowe informacje.

Aktualizacja 20170119 : Postanowiłem zaimplementować dekodowanie ukierunkowania, które działa zarówno dla Pythona 2, jak i Pythona 3. Powinien być wolniejszy niż roztwór {X0}}, ale powinien wytworzyć identyczne wyniki w każdej wersji Pythona.

# --- 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'))
105
Peter Mortensen 28 wrzesień 2019, 10:58

W Pythonie 3 domyślnym kodowaniem jest "utf-8" , więc możesz bezpośrednio użyć:

b'hello'.decode()

Co jest równoważne z

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

Z drugiej strony, w Python 2 kodowanie domyślne do Domyślne kodowanie łańcucha. Tak więc należy użyć:

b'hello'.decode(encoding)

Gdzie encoding jest kodowaniem, który chcesz.

Uwaga: wsparcie dla argumentów słów kluczowych został dodany w Pythonie 2.7.

94
Peter Mortensen 28 wrzesień 2019, 10:59

Myślę, że tak naprawdę chcesz:

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

Odpowiedź Aarona była poprawna, z wyjątkiem tego, że musisz znać , który kodowanie kodowania. I uważam, że system Windows używa "Windows-1252". Będzie on tylko kwestionować, jeśli masz jakieś niezwykłe (nie-ASCII) znaków w treści, ale wtedy coś zmienia.

Nawiasem mówiąc, fakt, że ona jest sprawa jest powodem, dla którego Python przeniósł się do używania dwóch różnych typów do danych binarnych i tekstowych: nie może konwertować magicznie między nimi, ponieważ nie zna Kodowanie, chyba że powiesz to! Jedynym sposobem, w jaki chcesz przeczytać dokumentację Windows (lub przeczytać ją tutaj).

43
Peter Mortensen 28 wrzesień 2019, 10:54

Ustaw Universal_Newlines na true, tj.

command_stdout = Popen(['ls', '-l'], stdout=PIPE, universal_newlines=True).communicate()[0]
34
Borislav Sabev 21 styczeń 2014, 15:47

Ponieważ to pytanie jest faktycznie pytanie o wyjście subprocess, masz bardziej bezpośrednie podejście dostępne od Popen akceptuje Kodowanie Słowo kluczowe (w Pythonie 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

Ogólna odpowiedź dla innych użytkowników jest Decode bajtów do tekstu:

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

Bez argumentu, sys.getdefaultencoding() zostanie użyta. Jeśli dane nie są sys.getdefaultencoding(), należy określić kodowanie jawnie w {x2}} zadzwoń:

>>> b'caf\xe9'.decode('cp1250')
'café'
25
wim 4 wrzesień 2020, 18:35

Podczas gdy Odpowiedź @aaron Maenpaa Wystarczy, użytkownik Niedawno zapytano:

Czy jest już taki prosty? "Fand.Read (). Decode (" ASCII ")" [...] Jest tak długi!

Możesz użyć:

command_stdout.decode()

decode() ma Standardowy argument :

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

24
Felipe Augusto 10 czerwiec 2019, 16:04

Jeśli powinieneś otrzymać następujące czynności, próbując decode():

AttritaError: Obiekt "Str" nie ma atrybutu "dekodowania"

Możesz także określić typ kodowania prosto w obsadzie:

>>> my_byte_str
b'Hello World'

>>> str(my_byte_str, 'utf-8')
'Hello World'
13
Felipe Augusto 10 czerwiec 2019, 16:03

Zrobiłem funkcję do czyszczenia listy

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
6
Tshilidzi Mudau 9 marzec 2017, 10:03

Podczas pracy z danymi z systemów Windows (za pomocą \r\n zakończenia linii), moja odpowiedź jest

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

Dlaczego? Spróbuj tego za pomocą multiline wejściem.txt:

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

Wszystkie zakończenia linii zostaną podwojone (do {x0}}), prowadząc do dodatkowych pustych linii. Funkcje do odczytu Pythona zwykle normalizują zakończenia linii, dzięki czemu struny używają tylko \n. Jeśli otrzymasz dane binarne z systemu Windows, Python nie ma szans na to. A zatem,

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

Powtórzy twój oryginalny plik.

6
bers 16 marzec 2018, 13:28

Dla Pythona 3, jest to znacznie bezpieczniejsze i Pythonic do konwersji z byte do string:

def byte_to_str(bytes_or_str):
    if isinstance(bytes_or_str, bytes): # Check if it's 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')

Wynik:

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
6
Peter Mortensen 28 wrzesień 2019, 11:11

W przypadku konkretnej przypadek "Uruchom polecenia powłoki i uzyskaj wyjście jako tekst zamiast bajtów", na Pythonie 3.7, powinieneś użyć subprocess.run i przejść w text=True (jak również capture_output=True, aby uchwycić wyjście)

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

text kiedyś nazywany universal_newlines i został zmieniony (dobrze, aliased) w Pythonie 3.7. Jeśli chcesz obsługiwać wersje Pythona przed 3,7, przejść w universal_newlines=True zamiast text=True

4
Boris 7 sierpień 2019, 19:51

Z SYS - parametry i funkcje specyficzne dla systemu :

Aby napisać lub odczytać dane binarne z / do standardowych strumieni, użyj podstawowego bufora binarnego. Na przykład, napisać bajty do stdout, użyj sys.stdout.buffer.write(b'abc').

4
Peter Mortensen 28 wrzesień 2019, 10:54
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))
2
Leonardo Filipe 3 czerwiec 2018, 22:44

Jeśli chcesz przekonwertować dowolne bajty, a nie tylko ciąg przekształcony na bajty:

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

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

Nie jest to jednak zbyt wydajne. Włączy obraz 2 MB na 9 MB.

2
Peter Mortensen 28 wrzesień 2019, 11:14

Spróbuj tego

bytes.fromhex('c3a9').decode('utf-8') 
2
Victor Choy 19 styczeń 2020, 08:19