I'm menggunakan kode ini untuk mendapatkan standar output dari program eksternal:
>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
Berkomunikasi() method ini mengembalikan sebuah array dari byte:
>>> 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'
Namun, saya'd seperti untuk bekerja dengan output normal Python string. Sehingga saya bisa mencetak seperti ini:
>>> 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
Saya berpikir bahwa's apa binascii.b2a_qp() metode ini, tetapi ketika saya mencobanya, saya punya sama byte array lagi:
>>> 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'
Bagaimana cara mengkonversi byte nilai kembali ke string? Maksud saya, menggunakan "baterai" alih-alih melakukannya secara manual. Dan saya'a seperti itu akan OK dengan Python 3.
Anda perlu untuk memecahkan kode byte objek untuk menghasilkan sebuah string:
>>> 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'
Anda perlu untuk memecahkan kode byte string dan mengubahnya ke sebuah karakter (Unicode) string.
Pada Python 2
encoding = 'utf-8'
'hello'.decode(encoding)
atau
unicode('hello', encoding)
Pada Python 3
encoding = 'utf-8'
b'hello'.decode(encoding)
atau
str(b'hello', encoding)
Jika anda don't tahu di encoding, maka untuk membaca input biner ke string di Python 3 dan Python 2 cara yang kompatibel, gunakan kuno MS-DOS CP437 encoding:
PY3K = sys.version_info >= (3, 0)
lines = []
for line in stream:
if not PY3K:
lines.append(line)
else:
lines.append(line.decode('cp437'))
Karena encoding ini tidak diketahui, mengharapkan non-bahasa inggris untuk menerjemahkan simbol-simbol untuk karakter cp437
(karakter bahasa inggris yang tidak diterjemahkan, karena mereka cocok dalam banyak byte tunggal pengkodean UTF-8).
Decoding sewenang-wenang input biner ke UTF-8 lebih aman, karena anda mungkin mendapatkan ini:
>>> 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
Hal yang sama berlaku untuk latin-1
, yang populer (default?) untuk Python versi 2. Melihat poin yang hilang di Codepage tata Letak - itu adalah di mana Python tersedak dengan terkenal ordinal tidak dalam jangkauan
.
UPDATE 20150604: Ada rumor bahwa Python 3 memiliki surrogateescape
kesalahan strategi untuk pengkodean barang-barang ke dalam data biner tanpa kehilangan data dan crash, tapi perlu konversi tes, [binary] -> [str] -> [binary]
, untuk memvalidasi kinerja dan kehandalan.
UPDATE 20170116: Terima kasih untuk komentar oleh Nearoo - ada juga kemungkinan untuk memangkas melarikan diri semua byte diketahui dengan backslashreplace
error handler. Yang bekerja hanya untuk Python 3, sehingga bahkan dengan solusi ini anda masih akan mendapatkan output yang tidak konsisten dari berbagai versi Python:
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'))
Melihat Python Dukungan Unicode untuk rincian.
UPDATE 20170119: aku memutuskan untuk menerapkan slash melarikan diri decode yang bekerja untuk kedua Python 2 dan Python 3. Itu harus lebih lambat dari cp437
solusi, tetapi harus menghasilkan hasil identik pada setiap Python versi.
# --- 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'))
Di Python 3, pengkodean default adalah "utf-8"
, sehingga anda dapat langsung menggunakan:
b'hello'.decode()
yang setara dengan
b'hello'.decode(encoding="utf-8")
Di sisi lain, di Python 2, pengkodean default default string encoding. Dengan demikian, anda harus menggunakan:
b'hello'.decode(encoding)
di mana encoding
adalah penyandian yang anda inginkan.
Catatan: dukungan untuk kata kunci argumen ditambahkan pada Python 2.7.
Saya pikir anda benar-benar ingin ini:
>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
>>> command_text = command_stdout.decode(encoding='windows-1252')
Harun's jawaban adalah benar, kecuali yang perlu anda ketahui yang encoding yang digunakan. Dan saya percaya bahwa Windows menggunakan 'windows-1252'. Itu hanya akan peduli jika anda memiliki beberapa yang tidak biasa (non-ASCII) karakter dalam konten anda, tapi kemudian itu akan membuat perbedaan.
By the way, fakta bahwa ini tidak masalah ini adalah alasan bahwa Python pindah ke menggunakan dua jenis yang berbeda untuk biner dan data teks: dapat't mengkonversi ajaib di antara mereka, karena itu doesn't tahu pengkodean kecuali kau katakan itu! Satu-satunya cara ANDA akan tahu untuk membaca dokumentasi Windows (atau baca di sini).
Sementara @Harun Maenpaa's jawaban hanya bekerja, pengguna baru-baru ini bertanya:
Apakah ada yang lebih sederhana? 'fhand.read().decode("ASCII")' [...] It's begitu lama!
Anda dapat menggunakan:
command_stdout.decode()
decode()
memiliki standar argumen:
codec.decode(obj, encoding='utf-8', kesalahan='yang ketat')
Karena pertanyaan ini benar-benar bertanya tentang subproses
output, anda memiliki pendekatan yang lebih langsung tersedia sejak Popen
menerima encoding kata kunci (dalam 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
Jawaban umum untuk pengguna lain untuk decode byte untuk teks:
>>> b'abcde'.decode()
'abcde'
Dengan tidak ada argumen, sys.getdefaultencoding()
yang akan digunakan. Jika data anda tidak sys.getdefaultencoding()
, maka anda harus menentukan encoding secara eksplisit dalam decode
call:
>>> b'caf\xe9'.decode('cp1250')
'café'
Untuk menafsirkan urutan byte sebagai teks, anda harus tahu sesuai karakter encoding:
unicode_text = bytestring.decode(character_encoding)
Contoh:
>>> b'\xc2\xb5'.decode('utf-8')
'µ'
ls
perintah dapat menghasilkan output yang dapat't diartikan sebagai teks. Nama File
pada Unix dapat setiap urutan dari byte kecuali slash b'/'
dan nol
b'\0'
:
>>> open(bytes(range(0x100)).translate(None, b'\0/'), 'w').close()
Mencoba untuk memecahkan kode seperti byte sup menggunakan utf-8 encoding menimbulkan UnicodeDecodeError
.
Itu dapat menjadi lebih buruk. Decoding mungkin gagal diam-diam dan menghasilkan mojibake jika anda menggunakan salah kompatibel encoding:
>>> '—'.encode('utf-8').decode('cp1252')
'—'
Data yang rusak tapi program anda tetap menyadari bahwa kegagalan telah terjadi.
Secara umum, apa pengkodean karakter yang digunakan tidak tertanam dalam urutan byte itu sendiri. Anda harus berkomunikasi info ini out-of-band. Beberapa hasil lebih mungkin daripada yang lain dan oleh karena itu chardet
modul ada yang bisa kira pengkodean karakter. Satu script Python dapat menggunakan beberapa pengkodean karakter di tempat yang berbeda.
ls
output dapat dikonversi ke string Python menggunakan [os.fsdecode()
fungsi]() yang berhasil bahkan untuk undecodable
nama file (menggunakan
sys.getfilesystemencoding()
dan surrogateescape
error handler pada
Unix):
import os
import subprocess
output = os.fsdecode(subprocess.check_output('ls'))
Untuk mendapatkan yang asli byte, anda bisa menggunakan os.fsencode()
.
Jika anda melewati universal_newlines=True
parameter kemudian subproses
menggunakan
lokal.getpreferredencoding(Palsu)
untuk memecahkan kode byte misalnya, dapat
cp1252
pada Windows.
Untuk memecahkan kode byte stream on-the-fly,
io.TextIOWrapper()
bisa digunakan: contoh.
Perintah yang berbeda dapat menggunakan pengkodean karakter yang berbeda untuk mereka
output misalnya, dir
perintah internal (cmd
) dapat menggunakan cp437. Untuk men-decode-nya
output, anda bisa melewati pengkodean secara eksplisit (Python 3.6+):
output = subprocess.check_output('dir', shell=True, encoding='cp437')
Nama file mungkin berbeda dari os.listdir()
(yang menggunakan Windows
Unicode API) misalnya, '\xb6'
dapat diganti dengan '\x14'
—Python's
cp437 codec maps b'\x14'
untuk mengontrol karakter U+0014 bukan
U+00B6 (¶). Untuk mendukung nama file dengan sewenang-wenang karakter Unicode, lihat https://stackoverflow.com/q/33936074/4279
Jika anda harus mendapatkan berikut dengan mencoba decode()
:
AttributeError: 'str' objek memiliki atribut 'decode'
Anda juga dapat menentukan jenis pengkodean langsung di cor:
>>> my_byte_str
b'Hello World'
>>> str(my_byte_str, 'utf-8')
'Hello World'
Ketika bekerja dengan data dari sistem Windows (dengan \r\n
di akhir baris), jawaban saya adalah
String = Bytes.decode("utf-8").replace("\r\n", "\n")
Mengapa? Coba ini dengan multiline Input.txt:
Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8")
open("Output.txt", "w").write(String)
Semua akhir baris akan menjadi dua kali lipat (untuk \r\r\n
), yang mengarah ke extra baris kosong. Python's teks-baca fungsi biasanya menormalkan garis ujung sehingga string yang hanya menggunakan \n
. Jika anda menerima data biner dari sistem Windows, Python tidak memiliki kesempatan untuk melakukan itu. Dengan demikian,
Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8").replace("\r\n", "\n")
open("Output.txt", "w").write(String)
akan mereplikasi file asli anda.
Saya membuat sebuah fungsi untuk membersihkan daftar
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
Untuk Python 3, ini adalah jauh lebih aman dan Pythonic pendekatan untuk mengkonversi dari byte
untuk 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')
Output:
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
Dari sys — Sistem-parameter tertentu dan fungsi:
Untuk menulis atau membaca data biner dari/ke standar sungai, menggunakan underlying biner penyangga. Misalnya, untuk menulis byte ke stdout, gunakan sys.stdout.buffer.write(b'abc')
.
Jika anda ingin mengkonversi byte, tidak hanya dikonversi ke string byte:
with open("bytesfile", "rb") as infile:
str = base64.b85encode(imageFile.read())
with open("bytesfile", "rb") as infile:
str2 = json.dumps(list(infile.read()))
Ini sangat tidak efisien, namun. Ini akan mengubah 2 MB gambar menjadi 9 MB.
Untuk anda spesifik kasus "menjalankan perintah shell dan mendapatkan output sebagai teks, bukan byte", pada Python 3.7, anda harus menggunakan subproses.menjalankan
dan lulus dalam text=True
(serta capture_output=True
untuk menangkap output)
command_result = subprocess.run(["ls", "-l"], capture_output=True, text=True)
command_result.stdout # is a `str` containing your program's stdout
teks
biasa disebut universal_newlines
, dan diubah (baik, alias) di Python 3.7. Jika anda ingin mendukung Python versi sebelum 3.7, lulus dalam universal_newlines=True
bukan text=True