Konwertuj bajty na ciąg znaków
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 communicate() 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 zwykły łańcuch Pythona. Żebym mógł to wydrukować 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 to jest to binascii.metoda b2a_qp() jest dla, Ale kiedy próbowałem, znowu dostał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 skonwertować wartość bajtów z powrotem na łańcuch znaków? I znaczy, używając "baterii" zamiast robić to ręcznie. A ja bym chciał żeby było OK z Pythonem 3.
21 answers
Musisz zdekodować obiekt bajtów, aby wytworzyć łańcuch znaków:
>>> 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'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-24 18:14:12
Musisz zdekodować łańcuch bajtów i przekształcić go w łańcuch znaków (Unicode).
On Python 2
encoding = 'utf-8'
'hello'.decode(encoding)
Lub
unicode('hello', encoding)
On Python 3
encoding = 'utf-8'
b'hello'.decode(encoding)
Lub
str(b'hello', encoding)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-28 10:52:57
Myślę, że ta droga jest łatwa:
>>> bytes_data = [112, 52, 52]
>>> "".join(map(chr, bytes_data))
'p44'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-14 18:31:44
Jeśli nie znasz kodowania, to aby odczytać dane binarne do ciągu znaków w sposób zgodny z Pythonem 3 i Pythonem 2, Użyj starożytnego 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, należy oczekiwać, że symbole nie-angielskie będą tłumaczone na znaki cp437
(angielskie znaki nie są tłumaczone, ponieważ pasują do większości kodowań jednobajtowych i UTF-8).
Dekodowanie dowolnego wejścia binarnego do UTF-8 jest niebezpieczne, ponieważ możesz uzyskać to:
>>> 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
The to samo dotyczy latin-1
, który był popularny(domyślnie?) dla Pythona 2. Zobacz brakujące punkty w układ strony kodowej - to tutaj Python dławi się infamous ordinal not in range
.
UPDATE 20150604: istnieją pogłoski, że Python 3 ma strategię błędów surrogateescape
do kodowania rzeczy do danych binarnych bez utraty danych i awarii, ale potrzebuje testów konwersji, [binary] -> [str] -> [binary]
, aby zweryfikować zarówno wydajność, jak i niezawodność.
UPDATE 20170116 : Thanks to comment by Nearoo - istnieje również możliwość ukośnika escape wszystkich nieznanych bajtów za pomocą obsługi błędów backslashreplace
. To działa tylko w Pythonie 3, więc nawet z tym obejściem nadal będziesz otrzymywał niespójne wyniki 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'))
Zobacz obsługa Unicode Pythona Po szczegóły.
UPDATE 20170119 : zdecydowałem się zaimplementować dekodowanie ukośnika, które działa zarówno dla Pythona 2, jak i Pythona 3. Powinno być wolniejsze niż rozwiązanie cp437
, ale powinno twórz identyczne wyniki dla 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'))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-28 10:58:53
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
b'hello'.decode(encoding="utf-8")
Z drugiej strony, w Pythonie 2 , encoding defaults to the default string encoding. Dlatego należy użyć:
b'hello'.decode(encoding)
Gdzie encoding
jest kodowaniem, które chcesz.
Uwaga: wsparcie dla argumentów słów kluczowych zostało dodane w Pythonie 2.7.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-28 10:59:43
Myślę, że naprawdę tego 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, tyle że musisz wiedzieć Jakie kodowanie użyć. A ja uważam, że Windows używa 'windows-1252'. Będzie to miało znaczenie tylko wtedy, gdy masz jakieś nietypowe (Nie-ASCII) znaki w treści, ale to będzie miało znaczenie.
Nawiasem mówiąc, fakt, że robi ma znaczenie, jest powodem, dla którego Python przeniósł się do używania dwóch różnych typów danych binarnych i tekstowych: nie może konwertować magicznie między nimi, bo nie zna kodowania, chyba że mu powiesz! Jedynym sposobem jest przeczytanie dokumentacji systemu Windows(lub przeczytanie jej tutaj).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-28 10:54:06
Ustaw universal_newlines na True, tzn.
command_stdout = Popen(['ls', '-l'], stdout=PIPE, universal_newlines=True).communicate()[0]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-21 15:47:48
Aby zinterpretować sekwencję bajtów 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 generować dane wyjściowe, które nie mogą być interpretowane jako tekst. Nazwy plików
na Unixie może być dowolna sekwencja bajtów z wyjątkiem slash b'/'
i zero
b'\0'
:
>>> open(bytes(range(0x100)).translate(None, b'\0/'), 'w').close()
Próba dekodowania takiego bajtu za pomocą kodowania utf-8 podnosi UnicodeDecodeError
.
>>> '—'.encode('utf-8').decode('cp1252')
'—'
Dane są uszkodzone, ale twój program pozostaje nieświadomy, że awaria wystąpił.
Ogólnie rzecz biorąc, kodowanie znaków nie jest osadzone w samej sekwencji bajtów. Musisz przekazać te informacje poza pasmem. Niektóre wyniki są bardziej prawdopodobne niż inne i dlatego istnieje chardet
moduł, który może odgadnąć kodowanie znaków. Pojedynczy skrypt Pythona może używać wielu kodowań znaków w różnych miejsca.
ls
Dane wyjściowe można przekonwertować na ciąg Pythona za pomocą os.fsdecode()
funkcja, która powiedzie się nawet dla undekodable
nazwy plików (używa
sys.getfilesystemencoding()
i surrogateescape
obsługa błędów na
Unix):
import os
import subprocess
output = os.fsdecode(subprocess.check_output('ls'))
Aby uzyskać oryginalne bajty, możesz użyć os.fsencode()
.
If you pass universal_newlines=True
parameter then subprocess
uses
locale.getpreferredencoding(False)
aby dekodować bajty np. można
cp1252
w systemie Windows.
Aby dekodować strumień bajtów w locie,
io.TextIOWrapper()
może być używany: przykład .
Różne komendy mogą używać różnych kodowań znaków dla swoich
wyjście np. dir
wewnętrzne polecenie (cmd
) może używać cp437. Aby rozszyfrować jego
wyjście, można przekazać kodowanie jawnie (Python 3.6+):
output = subprocess.check_output('dir', shell=True, encoding='cp437')
Nazwy plików mogą różnić się od os.listdir()
(który używa systemu Windows
Unicode API) np. '\xb6'
można zastąpić '\x14'
-Python ' s
cp437 kodek mapuje b'\x14'
do kontrolowania znaku U + 0014 zamiast
U + 00B6 (¶). Do obsługi nazw plików z dowolnymi Znaki Unicode, zobacz dekodowanie wyjścia PowerShell prawdopodobnie zawierającego znaki Unicode inne niż ASCII do łańcucha Pythona
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-04 20:19:44
Ponieważ to pytanie jest właściwie pytaniem o wyjście subprocess
, masz bardziej bezpośrednie podejście dostępne. Najnowocześniejsze byłoby wykorzystanie subprocess.check_output
i przekazywanie text=True
(Python 3.7+) do automatycznego dekodowania stdout przy użyciu domyślnego kodowania systemu:
text = subprocess.check_output(["ls", "-l"], text=True)
Dla Pythona 3.6, Popen
przyjmuje kodowanie słowo kluczowe:
>>> 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ólną odpowiedzią na pytanie w tytule, jeśli nie masz do czynienia z podprocesowym wyjściem, jest dekodowanie bajtów do tekst:
>>> b'abcde'.decode()
'abcde'
Bez argumentu, sys.getdefaultencoding()
zostaną wykorzystane. Jeśli Twoje dane nie są sys.getdefaultencoding()
, to musisz jawnie określić kodowanie wdecode
wywołanie:
>>> b'caf\xe9'.decode('cp1250')
'café'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-04 18:35:32
While @ Aaron Maenpaa ' s answer just works, a user recently asked :
Czy jest jakiś prosty sposób? "fhand.read ().decode("ASCII")" [... Tak długo!
Możesz użyć:
command_stdout.decode()
decode()
mA standardowy argument :
codecs.decode(obj, encoding='utf-8', errors='strict')
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-10 16:04:48
Jeśli powinieneś uzyskać następujące, próbując decode()
:
AttributeError:' str 'obiekt nie ma atrybutu 'decode'
Możesz również określić typ kodowania prosto w obsadzie:
>>> my_byte_str
b'Hello World'
>>> str(my_byte_str, 'utf-8')
'Hello World'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-10 16:03:10
I made a function to clean a list
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-09 10:03:11
Podczas pracy z danymi z systemów Windows (z zakończeniami linii \r\n
), moja odpowiedź brzmi
String = Bytes.decode("utf-8").replace("\r\n", "\n")
Dlaczego? Spróbuj tego z wejściem wielowierszowym.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 \r\r\n
), co doprowadzi do dodatkowych pustych linii. Funkcje odczytu tekstu Pythona Zwykle normalizują zakończenia linii, tak że ciągi używają tylko \n
. Jeśli otrzymujesz dane binarne z systemu Windows, Python nie ma na to szans. Zatem
Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8").replace("\r\n", "\n")
open("Output.txt", "w").write(String)
Powieli oryginalny plik.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-16 13:28:25
Dla Pythona 3 jest to znacznie bezpieczniejsze i Pythoniczne podejście do konwersji z byte
na 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')
Wyjście:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-28 11:11:58
Dla Twojego konkretnego 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
(jak również capture_output=True
, aby przechwycić 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
był nazywany universal_newlines
i został zmieniony (dobrze, aliased) w Pythonie 3.7. Jeśli chcesz obsługiwać wersje Pythona przed 3.7, podaj universal_newlines=True
zamiast text=True
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-07 19:51:33
Od sys-parametry i funkcje specyficzne dla Systemu:
Aby zapisać lub odczytać dane binarne z / do standardowych strumieni, użyj bazowego bufora binarnego. Na przykład, aby zapisać bajty na stdout, użyj sys.stdout.buffer.write(b'abc')
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-28 10:54:56
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))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-03 22:44:45
Jeśli chcesz przekonwertować dowolne bajty, a nie tylko łańcuch skonwertowany 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 efektywne. Zamieni obraz z 2 MB na 9 MB.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-28 11:14:40
Spróbuj tego
bytes.fromhex('c3a9').decode('utf-8')
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-19 08:19:02
Możesz to zrobić:
bstr=b'your string'
print(bstr.decode())
Wyjście:
your string
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-29 09:00:00
Możesz po prostu zrobić:
print(command_stdout.decode('utf-8'))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-22 14:18:18