Pertanyaan Konversi byte menjadi string?


Saya menggunakan kode ini untuk mendapatkan output standar dari program eksternal:

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

Metode communic () 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 yang binascii.b2a_qp () metode untuk, tetapi ketika saya mencobanya, saya mendapat susunan 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'

Apakah ada yang tahu cara mengubah nilai byte kembali ke string? Maksud saya, menggunakan "baterai" daripada melakukannya secara manual. Dan saya ingin itu baik-baik saja dengan Python 3.


1236
2018-03-03 12:23


asal


Jawaban:


Anda perlu mendekode objek byte untuk menghasilkan 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'

2036
2018-03-03 12:26



Saya pikir cara ini mudah:

bytes = [112, 52, 52]
"".join(map(chr, bytes))
>> p44

119
2017-08-22 12:57



Anda perlu men-decode string byte dan mengubahnya ke string karakter (unicode).

b'hello'.decode(encoding)

atau

str(b'hello', encoding)

99
2018-03-03 12:28



Jika Anda tidak tahu pengkodean, maka untuk membaca input biner ke string dengan Python 3 dan Python 2 cara yang kompatibel, gunakan MS-DOS kuno 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 pengkodean tidak diketahui, mengharapkan simbol non-bahasa Inggris untuk menerjemahkan ke karakter cp437 (Chars bahasa Inggris tidak diterjemahkan, karena mereka cocok dalam kebanyakan pengkodean byte tunggal dan UTF-8).

Mendekodasikan masukan biner yang sewenang-wenang ke UTF-8 tidak 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 2. Lihat poin yang hilang di Tata Letak Codepage - Di sinilah Python tersedak dengan kejam ordinal not in range.

PERBARUI 20150604: Ada desas-desus bahwa Python 3 memiliki surrogateescape strategi kesalahan untuk mengenkode data menjadi data biner tanpa kehilangan data dan macet, tetapi perlu tes konversi [binary] -> [str] -> [binary] untuk memvalidasi kinerja dan keandalan.

PERBARUI 20170116: Terima kasih atas komentar oleh Nearoo - ada juga kemungkinan untuk memangkas semua byte yang tidak diketahui backslashreplace kesalahan handler. Itu hanya berfungsi untuk Python 3, jadi dengan solusi ini Anda masih akan mendapatkan hasil yang tidak konsisten dari versi Python yang berbeda:

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

Lihat https://docs.python.org/3/howto/unicode.html#python-s-unicode-support untuk detailnya.

PERBARUI 20170119: Saya memutuskan untuk mengimplementasikan decode slash escape yang berfungsi baik untuk Python 2 dan Python 3. Seharusnya lebih lambat cp437 solusi, tetapi harus menghasilkan hasil yang identik pada setiap versi Python.

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

57
2017-12-17 14:23



Saya pikir apa yang sebenarnya Anda inginkan adalah ini:

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

Jawaban Aaron benar, kecuali bahwa Anda perlu tahu pengkodean WHICH mana yang akan digunakan. Dan saya percaya bahwa Windows menggunakan 'windows-1252'. Itu hanya masalah jika Anda memiliki beberapa karakter yang tidak biasa (non-ascii) dalam konten Anda, tetapi kemudian itu akan membuat perbedaan.

By the way, fakta bahwa itu tidak masalah adalah alasan bahwa Python pindah ke menggunakan dua jenis berbeda untuk data biner dan teks: itu tidak dapat mengkonversi secara ajaib di antara mereka karena tidak tahu pengkodean kecuali Anda menceritakannya! Satu-satunya cara yang Anda ketahui adalah membaca dokumentasi Windows (atau baca di sini).


32
2017-07-18 19:51



Dengan Python 3, pengkodean default adalah "utf-8", sehingga Anda dapat menggunakan secara langsung:

b'hello'.decode()

yang setara dengan

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

Di samping itu, dengan Python 2, encoding default ke pengkodean string default. Jadi, Anda harus menggunakan:

b'hello'.decode(encoding)

dimana encoding adalah pengkodean yang Anda inginkan.

catatan: dukungan untuk argumen kata kunci ditambahkan dengan Python 2.7.


30
2018-06-29 14:21



Tetapkan universal_newlines ke True, yaitu

command_stdout = Popen(['ls', '-l'], stdout=PIPE, universal_newlines=True).communicate()[0]

26
2018-01-21 15:31



Sementara Jawaban @Aaron Maenpaa hanya berfungsi, seorang pengguna baru-baru ini ditanyakan

Apakah ada cara lain yang lebih mudah? 'fhand.read (). decode ("ASCII")' [...] Begitu lama!

Kamu dapat memakai

command_stdout.decode()

decode() mempunyai sebuah argumen standar

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


15
2017-11-13 10:24



Untuk menafsirkan urutan byte sebagai teks, Anda harus tahu pengkodean karakter yang sesuai:

unicode_text = bytestring.decode(character_encoding)

Contoh:

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

ls perintah dapat menghasilkan output yang tidak dapat ditafsirkan sebagai teks. Nama file di Unix dapat berupa urutan byte kecuali slash b'/' dan nol b'\0':

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

Mencoba untuk memecahkan kode sup byte tersebut menggunakan utf-8 encoding raises UnicodeDecodeError.

Itu bisa lebih buruk. Penguraian kode dapat gagal secara diam-diam dan menghasilkan mojibake jika Anda menggunakan pengkodean tidak kompatibel yang salah:

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

Data rusak tetapi program Anda tetap tidak menyadari bahwa kegagalan telah terjadi.

Secara umum, pengkodean karakter apa yang digunakan tidak tertanam dalam urutan byte itu sendiri. Anda harus mengkomunikasikan info ini dari-band. Beberapa hasil lebih mungkin daripada yang lain dan karenanya chardet ada modul yang bisa kira pengkodean karakter. Skrip Python tunggal dapat menggunakan pengkodean banyak karakter di tempat yang berbeda.


ls output dapat dikonversi ke string Python menggunakan os.fsdecode() fungsi yang berhasil bahkan untuk tidak bisa dikodekan nama file (Itu menggunakan sys.getfilesystemencoding() dan surrogateescape error handler Unix):

import os
import subprocess

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

Untuk mendapatkan byte asli, Anda bisa menggunakan os.fsencode().

Jika Anda lulus universal_newlines=True parameter itu subprocess menggunakan locale.getpreferredencoding(False) untuk memecahkan kode byte, mis., bisa cp1252 di Windows.

Untuk memecahkan kode aliran byte on-the-fly, io.TextIOWrapper() bisa digunakan: contoh.

Perintah yang berbeda dapat menggunakan pengkodean karakter yang berbeda untuk mereka keluaran misalnya, dir perintah internal (cmd) dapat menggunakan cp437. Untuk memecahkan kode-nya output, Anda bisa melewati pengkodean secara eksplisit (Python 3.6+):

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

Nama file mungkin berbeda os.listdir() (yang menggunakan Windows API Unicode) mis., '\xb6' dapat diganti dengan '\x14'—Petangga cp437 codec maps b'\x14' untuk mengendalikan karakter U + 0014 sebagai gantinya U + 00B6 (¶). Untuk mendukung nama file dengan karakter Unicode sewenang-wenang, lihat Output poweshell dekode mungkin berisi karakter unicode unicode ke dalam string python


10
2017-11-16 09:43



Jika Anda harus mendapatkan yang berikut dengan mencoba decode():

AttributeError: 'str' object has no attribute 'decode'

Anda juga dapat menentukan jenis pengkodean langsung dalam gips:

>>> my_byte_str
b'Hello World'

>>> str(my_byte_str, 'utf-8')
'Hello World'

5
2017-11-22 04:20