Saya menggunakan kode ini untuk mendapatkan output standar dari program eksternal:
>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
Metode berkomunikasi () mengembalikan array 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 ingin bekerja dengan output sebagai string Python normal. Sehingga saya bisa mencetaknya 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 pikir itulah gunanya metode binascii.b2a_qp () , tetapi ketika saya mencobanya, saya mendapatkan array byte yang sama 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 mengubah nilai byte kembali ke string? Maksud saya, menggunakan "baterai" alih-alih melakukannya secara manual. Dan saya ingin itu baik-baik saja dengan Python 3.
python
string
python-3.x
Tomas Sedovic
sumber
sumber
str(text_bytes)
bekerja Ini sepertinya aneh bagi saya.str(text_bytes)
tidak dapat menentukan pengkodean. Bergantung pada apa yang ada di text_bytes,text_bytes.decode('cp1250
) `mungkin menghasilkan string yang sangat berbedatext_bytes.decode('utf-8')
.str
fungsi tidak dikonversi menjadi string nyata lagi. Seseorang HARUS mengatakan penyandian secara eksplisit untuk beberapa alasan saya malas membaca alasannya. Konversikan keutf-8
dan lihat apakah kode ur Anda berfungsi. mis.var = var.decode('utf-8')
unicode_text = str(bytestring, character_encoding)
berfungsi seperti yang diharapkan pada Python 3. Meskipununicode_text = bytestring.decode(character_encoding)
lebih disukai untuk menghindari kebingungan dengan hanyastr(bytes_obj)
yang menghasilkan representasi teks untukbytes_obj
daripada mendekodekan ke teks:str(b'\xb6', 'cp1252') == b'\xb6'.decode('cp1252') == '¶'
danstr(b'\xb6') == "b'\\xb6'" == repr(b'\xb6') != '¶'
Jawaban:
Anda perlu mendekode objek byte untuk menghasilkan string:
sumber
"windows-1252"
juga tidak dapat diandalkan (misalnya, untuk Windows versi bahasa lainnya), bukankah lebih baik digunakansys.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
konversi cenderung gagal. Alih-alih lihat jawaban @techtonik (di bawah) stackoverflow.com/a/27527728/198536Anda perlu men-decode string byte dan mengubahnya menjadi string karakter (Unicode).
Di Python 2
atau
Di Python 3
atau
sumber
variable = b'hello'
, makaunicode_text = variable.decode(character_encoding)
Saya pikir cara ini mudah:
sumber
bytes([112, 52, 52])
- byte btw adalah nama yang buruk untuk variabel lokal persis karena itu adalah p3 builtinJika Anda tidak tahu pengkodeannya, maka untuk membaca input biner ke dalam string dengan cara yang kompatibel dengan Python 3 dan Python 2, gunakan pengkodean MS-DOS CP437 kuno :
Karena pengodean tidak diketahui, harap simbol non-Inggris untuk menerjemahkan ke karakter
cp437
(karakter bahasa Inggris tidak diterjemahkan, karena mereka cocok di sebagian besar pengkodean byte tunggal dan UTF-8).Mendekode input biner acak ke UTF-8 tidak aman, karena Anda mungkin mendapatkan ini:
Hal yang sama berlaku untuk
latin-1
, yang populer (default?) Untuk Python 2. Lihat poin yang hilang dalam Tata Letak Codepage - ini adalah tempat Python tersedak dengan terkenalordinal not in range
.UPDATE 20150604 : Ada desas-desus bahwa Python 3 memiliki
surrogateescape
strategi kesalahan untuk pengkodean hal-hal menjadi data biner tanpa kehilangan data dan crash, tetapi perlu tes konversi[binary] -> [str] -> [binary]
,, untuk memvalidasi kinerja dan keandalan.UPDATE 20170116 : Berkat komentar dari Nearoo - ada juga kemungkinan untuk memangkas semua byte yang tidak diketahui dengan
backslashreplace
penangan kesalahan. Itu hanya berfungsi untuk Python 3, jadi meskipun dengan solusi ini Anda masih akan mendapatkan output yang tidak konsisten dari versi Python yang berbeda:Lihat Dukungan Unicode Python untuk detailnya.
UPDATE 20170119 : Saya memutuskan untuk mengimplementasikan slash escaping decode yang berfungsi baik untuk Python 2 dan Python 3. Seharusnya lebih lambat daripada
cp437
solusinya, tetapi harus menghasilkan hasil yang identik pada setiap versi Python.sumber
b'\x00\x01\xffsd'.decode('utf-8', 'ignore')
python 3.b'\x80abc'.decode("utf-8", "backslashreplace")
akan menghasilkan'\\x80abc'
. Informasi ini diambil dari halaman dokumentasi unicode yang tampaknya telah diperbarui sejak penulisan jawaban ini.Di Python 3 , penyandian default adalah
"utf-8"
, sehingga Anda dapat langsung menggunakan:yang setara dengan
Di sisi lain, dalam Python 2 , pengkodean default ke pengkodean string default. Jadi, Anda harus menggunakan:
di mana
encoding
pengkodean yang Anda inginkan.Catatan: dukungan untuk argumen kata kunci ditambahkan dalam Python 2.7.
sumber
Saya pikir Anda benar-benar menginginkan ini:
Jawaban Harun benar, kecuali bahwa Anda perlu tahu pengkodean mana yang harus digunakan. Dan saya percaya bahwa Windows menggunakan 'windows-1252'. Itu hanya masalah jika Anda memiliki beberapa karakter yang tidak biasa (non-ASCII) di konten Anda, tetapi kemudian akan membuat perbedaan.
By the way, fakta bahwa itu tidak peduli adalah alasan bahwa Python pindah ke menggunakan dua jenis yang berbeda untuk data biner dan teks: tidak dapat mengkonversi ajaib di antara mereka, karena tidak tahu pengkodean kecuali Anda kirim! Satu-satunya cara ANDA akan tahu adalah membaca dokumentasi Windows (atau membacanya di sini).
sumber
open()
berfungsi untuk stream teks atauPopen()
jika Anda lulusuniversal_newlines=True
secara ajaib memutuskan pengkodean karakter untuk Anda (locale.getpreferredencoding(False)
dalam Python 3.3+)'latin-1'
adalah pengkodean kata demi kata dengan semua titik kode yang diatur, sehingga Anda dapat menggunakannya untuk secara efektif membaca string byte ke jenis string mana pun yang didukung oleh Python Anda (jadi kata demi kata di Python 2, ke dalam Unicode untuk Python 3).'latin-1'
adalah cara yang baik untuk mendapatkan mojibake. Juga ada substitusi magis pada Windows: itu mengejutkan sulit data pipa dari satu proses ke yang lain misalnya dimodifikasi,dir
:\xb6
->\x14
(contoh pada akhir jawaban saya)Set universal_newlines ke True, yaitu
sumber
text=True
bukanuniversal_newlines=True
.Sementara jawaban @Aaron Maenpaa hanya berfungsi, pengguna baru-baru ini bertanya :
Kamu bisa menggunakan:
decode()
memiliki argumen standar :sumber
.decode()
yang menggunakan'utf-8'
mungkin gagal (output perintah dapat menggunakan pengkodean karakter yang berbeda atau bahkan mengembalikan urutan byte yang tidak dapat didekodekan). Padahal jika inputnya adalah ascii (subset dari utf-8) maka.decode()
berfungsi.Untuk menafsirkan urutan byte sebagai teks, Anda harus mengetahui pengkodean karakter yang sesuai:
Contoh:
ls
perintah dapat menghasilkan output yang tidak dapat diartikan sebagai teks. Nama file di Unix dapat berupa urutan byte apa pun kecuali garis miringb'/'
dan nolb'\0'
:Mencoba untuk men-decode sup byte seperti itu menggunakan kenaikan gaji utf-8
UnicodeDecodeError
.Itu bisa lebih buruk. Dekoding mungkin gagal secara diam-diam dan menghasilkan mojibake jika Anda menggunakan penyandian yang tidak kompatibel yang salah:
Data rusak tetapi program Anda tetap tidak menyadari bahwa telah terjadi kegagalan.
Secara umum, pengkodean karakter apa yang digunakan tidak tertanam dalam urutan byte itu sendiri. Anda harus mengkomunikasikan info ini keluar-dari-band. Beberapa hasil lebih mungkin daripada yang lain dan karena itu
chardet
ada modul yang dapat menebak pengkodean karakter. Sebuah skrip Python tunggal dapat menggunakan beberapa pengkodean karakter di tempat yang berbeda.ls
output dapat dikonversi ke string Python menggunakanos.fsdecode()
fungsi yang berhasil bahkan untuk nama file yang tidak dapat didekodekan (menggunakansys.getfilesystemencoding()
dansurrogateescape
penangan kesalahan di Unix):Untuk mendapatkan byte asli, Anda bisa menggunakan
os.fsencode()
.Jika Anda melewatkan
universal_newlines=True
parameter kemudiansubprocess
gunakanlocale.getpreferredencoding(False)
untuk mendekode byte misalnya, itu bisacp1252
di Windows.Untuk mendekode byte stream on-the-fly,
io.TextIOWrapper()
dapat digunakan: contoh .Perintah yang berbeda dapat menggunakan pengkodean karakter yang berbeda untuk keluarannya misalnya,
dir
perintah internal (cmd
) dapat menggunakan cp437. Untuk mendekode outputnya, Anda bisa meneruskan penyandian secara eksplisit (Python 3.6+):Nama file mungkin berbeda dari
os.listdir()
(yang menggunakan Windows Unicode API) misalnya,'\xb6'
dapat diganti dengan'\x14'
peta codec cp437 -Pythonb'\x14'
untuk mengontrol karakter U + 0014 alih-alih U + 00B6 (¶). Untuk mendukung nama file dengan karakter Unicode yang arbitrer, lihat Decode PowerShell output yang mungkin mengandung karakter Unicode non-ASCII menjadi string Pythonsumber
Karena pertanyaan ini sebenarnya menanyakan tentang
subprocess
keluaran, Anda memiliki pendekatan yang lebih langsung karenaPopen
menerima kata kunci pengodean (dengan Python 3.6+):Jawaban umum untuk pengguna lain adalah mendekode byte ke teks:
Tanpa argumen,
sys.getdefaultencoding()
akan digunakan. Jika data Anda tidaksys.getdefaultencoding()
, maka Anda harus menentukan pengkodean secara eksplisit dalamdecode
panggilan:sumber
text=True
untuk mendekode stdin, stdout dan stderr menggunakan pengkodean yang diberikan (jika diatur) atau sistem default sebaliknya.Popen(['ls', '-l'], stdout=PIPE, text=True)
.ls
Output decoding menggunakanutf-8
encoding mungkin gagal (lihat contoh dalam jawaban saya dari 2016 ).encoding
parameter diberikan, makatext
parameter diabaikan.Jika Anda harus mendapatkan yang berikut dengan mencoba
decode()
:Anda juga dapat menentukan jenis penyandian lurus dalam gips:
sumber
Ketika bekerja dengan data dari sistem Windows (dengan
\r\n
ujung garis), jawaban saya adalahMengapa? Coba ini dengan Input.txt multiline:
Semua ujung garis Anda akan digandakan (ke
\r\r\n
), mengarah ke garis kosong ekstra. Fungsi membaca teks Python biasanya menormalkan akhir baris sehingga string hanya digunakan\n
. Jika Anda menerima data biner dari sistem Windows, Python tidak memiliki kesempatan untuk melakukan itu. Jadi,akan mereplikasi file asli Anda.
sumber
.replace("\r\n", "\n")
tambahan begitu lama. Ini adalah jawabannya jika Anda ingin merender HTML dengan benar.Saya membuat fungsi untuk membersihkan daftar
sumber
.strip
,.replace
,.encode
panggilan, dll dalam satu daftar pemahaman dan hanya iterate atas daftar sekali bukan iterasi itu lima kali.Untuk Python 3, ini adalah pendekatan yang jauh lebih aman dan Pythonic untuk dikonversi dari
byte
kestring
:Keluaran:
sumber
byte_to_str
" yang menyiratkan akan mengembalikan str, tetapi hanya mencetak nilai yang dikonversi, dan mencetak pesan kesalahan jika gagal (tetapi tidak menimbulkan pengecualian). Pendekatan ini juga unpythonic dan mengaburkanbytes.decode
solusi yang Anda berikan.Dari sys - Parameter dan fungsi khusus sistem :
Untuk menulis atau membaca data biner dari / ke stream standar, gunakan buffer biner yang mendasarinya. Misalnya, untuk menulis byte ke stdout, gunakan
sys.stdout.buffer.write(b'abc')
.sumber
bytes
.sumber
Untuk kasus spesifik Anda "jalankan perintah shell dan dapatkan output sebagai teks alih-alih byte", pada Python 3.7, Anda harus menggunakan
subprocess.run
dan meneruskantext=True
(dan jugacapture_output=True
untuk menangkap output)text
dulu dipanggiluniversal_newlines
, dan diubah (well, alias) dalam Python 3.7. Jika Anda ingin mendukung versi Python sebelum 3.7, berikanuniversal_newlines=True
alih-alihtext=True
sumber
Jika Anda ingin mengonversi byte apa pun, bukan hanya string yang dikonversi ke byte:
Namun, ini tidak terlalu efisien. Ini akan mengubah gambar 2 MB menjadi 9 MB.
sumber
coba ini
sumber