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 Communication () 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 danymi wyjściowymi jako normalnym ciągiem Python. Żebym mógł wydrukować to w ten sposób:
>>> 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 po to jest metoda binascii.b2a_qp () , ale kiedy spróbowałem, znów otrzymałem tę samą tablicę bajtów:
>>> 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 przekonwertować wartość bajtów z powrotem na ciąg? Mam na myśli używanie „baterii” zamiast robienia tego ręcznie. I chciałbym, żeby było dobrze w Pythonie 3.
python
string
python-3.x
Tomas Sedovic
źródło
źródło
str(text_bytes)
działa To wydaje mi się dziwne.str(text_bytes)
nie można określić kodowania. W zależności od tego, co jest w text_bytes,text_bytes.decode('cp1250
) `może spowodować bardzo inny ciąg znaków dotext_bytes.decode('utf-8')
.str
funkcja nie przekształca się już w prawdziwy ciąg. Z jakiegoś powodu MUSIMY wyraźnie powiedzieć kodowanie. Jestem leniwy, by przeczytać, dlaczego. Po prostu przekonwertuj goutf-8
i sprawdź, czy Twój kod działa. np.var = var.decode('utf-8')
unicode_text = str(bytestring, character_encoding)
działa zgodnie z oczekiwaniami w Pythonie 3. Chociażunicode_text = bytestring.decode(character_encoding)
bardziej preferowane jest unikanie pomyłek z tym,str(bytes_obj)
że tworzy reprezentację tekstowąbytes_obj
zamiast dekodowania jej do tekstu:str(b'\xb6', 'cp1252') == b'\xb6'.decode('cp1252') == '¶'
istr(b'\xb6') == "b'\\xb6'" == repr(b'\xb6') != '¶'
Odpowiedzi:
Musisz zdekodować obiekt bajtów, aby utworzyć ciąg znaków:
źródło
"windows-1252"
nie jest niezawodne (np. W przypadku innych wersji językowych systemu Windows), czy nie byłoby najlepiej używaćsys.stdout.encoding
?b"\x80\x02\x03".decode("utf-8")
->UnicodeDecodeError: 'utf8' codec can't decode byte 0x80 in position 0: invalid start byte
.utf-8
konwersja prawdopodobnie się nie powiedzie. Zamiast tego zobacz odpowiedź @techtonik (poniżej) stackoverflow.com/a/27527728/198536Musisz zdekodować ciąg bajtów i przekształcić go w ciąg znaków (Unicode).
W Pythonie 2
lub
W Pythonie 3
lub
źródło
variable = b'hello'
, tounicode_text = variable.decode(character_encoding)
Myślę, że ten sposób jest łatwy:
źródło
bytes([112, 52, 52])
- btw bajtów to zła nazwa zmiennej lokalnej właśnie dlatego, że jest to wbudowany p3Jeśli nie znasz kodowania, to aby wczytać dane binarne do łańcucha w sposób zgodny z Python 3 i Python 2, użyj starożytnego kodowania MS-DOS CP437 :
Ponieważ kodowanie jest nieznane, należy oczekiwać, że symbole w języku innym niż angielski
cp437
zostaną przetłumaczone na znaki (znaki angielskie nie są tłumaczone, ponieważ pasują do większości kodowań jednobajtowych i UTF-8).Dekodowanie dowolnego wejścia binarnego na UTF-8 jest niebezpieczne, ponieważ możesz otrzymać:
To samo dotyczy
latin-1
, który był popularny (domyślny?) W Pythonie 2. Zobacz brakujące punkty w Układzie strony kodowej - to tam Python dusi się z niesławąordinal not in range
.AKTUALIZACJA 20150604 : Istnieją pogłoski, że Python 3 ma
surrogateescape
strategię błędów do kodowania danych w danych binarnych bez utraty danych i awarii, ale wymaga testów konwersji[binary] -> [str] -> [binary]
, aby sprawdzić zarówno wydajność, jak i niezawodność.AKTUALIZACJA 20170116 : Dzięki komentarzowi Nearoo - istnieje również możliwość ukrycia ucieczki wszystkich nieznanych bajtów za pomocą
backslashreplace
procedury obsługi błędów. Działa to tylko w przypadku Python 3, więc nawet z tym obejściem nadal będziesz otrzymywać niespójne dane wyjściowe z różnych wersji Python:Aby uzyskać szczegółowe informacje, zobacz Obsługa Unicode w języku Python .
AKTUALIZACJA 20170119 : Postanowiłem zaimplementować ukośnik uciekający, który działa zarówno dla Pythona 2, jak i dla Pythona 3. Powinno być wolniejsze niż
cp437
rozwiązanie, ale powinno dawać identyczne wyniki dla każdej wersji Pythona.źródło
b'\x00\x01\xffsd'.decode('utf-8', 'ignore')
w pythonie 3.b'\x80abc'.decode("utf-8", "backslashreplace")
spowoduje'\\x80abc'
. Informacje te pochodzą ze strony dokumentacji Unicode, która wydaje się być zaktualizowana od czasu napisania tej odpowiedzi.W Pythonie 3 domyślnym kodowaniem jest
"utf-8"
, więc możesz bezpośrednio użyć:co jest równoważne z
Z drugiej strony, w Pythonie 2 , kodowanie jest domyślnie ustawione na domyślne kodowanie ciągu. Dlatego powinieneś użyć:
gdzie
encoding
jest kodowanie, które chcesz.Uwaga: obsługa argumentów słów kluczowych została dodana w Pythonie 2.7.
źródło
Myślę, że tak naprawdę chcesz:
Odpowiedź Aarona była poprawna, z tym wyjątkiem, że musisz wiedzieć, jakiego kodowania użyć. I wierzę, że Windows używa „Windows-1252”. Będzie to miało znaczenie tylko wtedy, gdy będziesz zawierał nietypowe (spoza ASCII) znaki w treści, ale wtedy coś zmieni.
Nawiasem mówiąc, fakt, że ma to znaczenie, jest powodem, dla którego Python przeszedł na używanie dwóch różnych typów danych binarnych i tekstowych: nie może konwertować magicznie między nimi, ponieważ nie zna kodowania, chyba że to powiesz! Jedyny sposób, w jaki MUSISZ wiedzieć, to przeczytać dokumentację Windows (lub przeczytać tutaj).
źródło
open()
funkcja dla strumieni tekstowych lubPopen()
jeśli ją przejdziesz,universal_newlines=True
magicznie zdecyduj o kodowaniu znaków dla Ciebie (locale.getpreferredencoding(False)
w Python 3.3+).'latin-1'
jest dosłownie kodowaniem ze wszystkimi ustawionymi punktami kodowymi, więc możesz go użyć, aby skutecznie odczytać ciąg bajtów do dowolnego typu ciągu obsługiwanego przez Python (tak dosłownie w Pythonie 2, w Unicode dla Pythona 3).'latin-1'
to dobry sposób na uzyskanie mojibake. Istnieją również magiczne podstawienia w systemie Windows: zaskakująco trudno jest przesyłać dane z jednego procesu do innego niezmodyfikowanego, np .dir
:\xb6
->\x14
(przykład na końcu mojej odpowiedzi)Ustaw universal_newlines na True, tj
źródło
text=True
zamiastuniversal_newlines=True
.Podczas gdy odpowiedź @Aaron Maenpaa po prostu działa, użytkownik niedawno zapytał :
Możesz użyć:
decode()
ma standardowy argument :źródło
.decode()
takie użycie'utf-8'
może się nie powieść (dane wyjściowe polecenia mogą używać innego kodowania znaków lub nawet zwrócić niezdefiniowaną sekwencję bajtów). Chociaż jeśli wejście to ascii (podzbiór utf-8), to.decode()
działa.Aby zinterpretować sekwencję bajtów jako tekst, musisz znać odpowiednie kodowanie znaków:
Przykład:
ls
polecenie może generować dane wyjściowe, których nie można interpretować jako tekstu. Nazwy plików w Uniksie mogą być dowolną sekwencją bajtów oprócz ukośnikab'/'
i zerab'\0'
:Próba odkodowania takiej bajtowej zupy przy użyciu kodowania utf-8 podnosi
UnicodeDecodeError
.Może być gorzej. Dekodowanie może się nie powieść po cichu i spowodować mojibake, jeśli użyjesz niewłaściwego niekompatybilnego kodowania:
Dane są uszkodzone, ale Twój program nie jest świadomy wystąpienia awarii.
Ogólnie, jakie kodowanie znaków do użycia nie jest osadzone w samej sekwencji bajtów. Musisz przekazać te informacje poza pasmem. Niektóre wyniki są bardziej prawdopodobne niż inne, dlatego
chardet
istnieje moduł, który może odgadnąć kodowanie znaków. Pojedynczy skrypt w języku Python może wykorzystywać kodowanie wielu znaków w różnych miejscach.ls
dane wyjściowe można przekonwertować na ciąg znaków w języku Python przy użyciuos.fsdecode()
funkcji, która działa nawet w przypadku niezdefiniowanych nazw plików (używasys.getfilesystemencoding()
isurrogateescape
obsługi błędów w systemie Unix):Aby uzyskać oryginalne bajty, możesz użyć
os.fsencode()
.Jeśli podasz
universal_newlines=True
parametr, a następniesubprocess
użyje golocale.getpreferredencoding(False)
do zdekodowania bajtów, np. Może to byćcp1252
system Windows.Do dekodowania strumienia bajtów w locie
io.TextIOWrapper()
można użyć: przykład .Różne polecenia mogą używać różnych kodowań znaków dla swoich danych wyjściowych, np.
dir
Polecenie wewnętrzne (cmd
) może używać cp437. Aby zdekodować jego dane wyjściowe, możesz przekazać kodowanie jawnie (Python 3.6+):Nazwy plików mogą różnić się od
os.listdir()
(który używa Windows Unicode API), np.'\xb6'
Można je zastąpić'\x14'
mapami koderów-cp437 firmy Python wb'\x14'
celu sterowania znakiem U + 0014 zamiast U + 00B6 (¶). Aby obsługiwać nazwy plików z dowolnymi znakami Unicode, zobacz Dekodowanie danych wyjściowych PowerShell, które mogą zawierać znaki Unicode inne niż ASCII do ciągu znaków w języku Pythonźródło
Ponieważ to pytanie faktycznie dotyczy
subprocess
danych wyjściowych, dostępne jest bardziej bezpośrednie podejście, ponieważPopen
akceptuje słowo kluczowe kodujące (w Python 3.6+):Ogólna odpowiedź dla innych użytkowników to dekodowanie bajtów na tekst:
Bez argumentu
sys.getdefaultencoding()
zostaną użyte. Jeśli Twoje dane nie sąsys.getdefaultencoding()
, musisz jawnie określić kodowanie wdecode
wywołaniu:źródło
text=True
do dekodowania stdin, stdout i stderr przy użyciu danego kodowania (jeśli jest ustawione) lub domyślnego systemu w innym przypadku.Popen(['ls', '-l'], stdout=PIPE, text=True)
.ls
danych wyjściowych przy użyciuutf-8
kodowania może się nie powieść (patrz przykład w mojej odpowiedzi z 2016 r .).encoding
parametr jest podany, wówczastext
parametr jest ignorowany.Jeśli powinieneś uzyskać następujące informacje, próbując
decode()
:Możesz także określić typ kodowania bezpośrednio w obsadzie:
źródło
Podczas pracy z danymi z systemów Windows (z
\r\n
zakończeniami linii) moja odpowiedź brzmiDlaczego? Wypróbuj to z multiline Input.txt:
Wszystkie zakończenia linii zostaną podwojone (do
\r\r\n
), co spowoduje dodatkowe puste linie. Funkcje odczytywania tekstu w Pythonie zwykle normalizują zakończenia linii, dzięki czemu używane są tylko łańcuchy\n
. Jeśli otrzymujesz dane binarne z systemu Windows, Python nie ma na to szans. A zatem,skopiuje twój oryginalny plik.
źródło
.replace("\r\n", "\n")
Tak długo szukałem dodatku. To jest odpowiedź, jeśli chcesz poprawnie renderować HTML.Zrobiłem funkcję czyszczenia listy
źródło
.strip
,.replace
,.encode
itp połączeń w jednym listowego i tylko iteracyjne nad listą raz zamiast iteracji po nim pięć razy.Dla Python 3, jest to o wiele bezpieczniejsze i pythonowy podejście przekonwertować z
byte
dostring
:Wynik:
źródło
byte_to_str
”, co oznacza, że zwróci ciąg, ale drukuje tylko skonwertowaną wartość i drukuje komunikat o błędzie, jeśli się nie powiedzie (ale nie zgłosi wyjątku). Takie podejście jest również pozbawione mitów i zaciemniabytes.decode
podane rozwiązanie.Z sys - parametry i funkcje specyficzne dla systemu :
Aby zapisać lub odczytać dane binarne ze / do standardowych strumieni, użyj bazowego bufora binarnego. Na przykład, aby zapisać bajty na standardowe wyjście, użyj
sys.stdout.buffer.write(b'abc')
.źródło
bytes
wartości wynikowej .źródło
W konkretnym przypadku „uruchom polecenie powłoki i uzyskaj jego wynik jako tekst zamiast bajtów”, w Pythonie 3.7 powinieneś użyć
subprocess.run
i przekazaćtext=True
(orazcapture_output=True
przechwycić dane wyjściowe)text
był wywoływanyuniversal_newlines
i był zmieniany (no cóż, alias) w Pythonie 3.7. Jeśli chcesz obsługiwać wersje Python starsze niż 3.7, podajuniversal_newlines=True
zamiasttext=True
źródło
Jeśli chcesz przekonwertować dowolne bajty, nie tylko ciąg znaków przekonwertowany na bajty:
Nie jest to jednak zbyt wydajne. Zmieni obraz o wielkości 2 MB na 9 MB.
źródło
Spróbuj tego
źródło