[python] 將字節轉換為字符串?


Answers

我認為這種方式很簡單:

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

我正在使用此代碼從外部程序獲取標準輸出:

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

通信()方法返回一個字節數組:

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

但是,我想用普通的Python字符串處理輸出。 這樣我可以像這樣打印它:

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

我認為這就是binascii.b2a_qp()方法的binascii.b2a_qp() ,但是當我嘗試它時,我又得到了相同的字節數組:

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

有誰知道如何將字節值轉換回字符串? 我的意思是,使用“電池”而不是手動進行。 我希望它能與Python 3一致。




在Python 3中,您可以直接使用:

b'hello'.decode()

相當於

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

這裡的默認編碼是“utf-8”,或者你可以通過以下方式檢查它:

>> import sys
>> sys.getdefaultencoding()



儘管@Aaron Maenpaa的答案正確,但最近一位用戶問道

有沒有更簡單的方法? 'fhand.read()。decode(“ASCII”)'[...]它太長了!

您可以使用

command_stdout.decode()

decode()有一個標準參數

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




我做了一個清理列表的函數

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



如果您不知道編碼,那麼要以Python 3和Python 2兼容的方式將二進制輸入讀入字符串,請使用古老的MS-DOS cp437編碼:

PY3K = sys.version_info >= (3, 0)

lines = []
for line in stream:
    if not PY3K:
        lines.append(line)
    else:
        lines.append(line.decode('cp437'))

由於編碼是未知的,期望非英文符號轉換為cp437字符(英文字符不翻譯,因為它們在大多數單字節編碼和UTF-8中匹配)。

將任意二進制輸入解碼為UTF-8是不安全的,因為你可能會得到這個:

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

這同樣適用於latin-1 ,這對於Python 2來說很流行(默認為?)。請參閱Codepage Layout中缺少的點 - 它是Python扼殺臭名昭著的ordinal not in range

更新20150604 :有傳言說Python 3有編碼東西到二進制數據沒有數據丟失和崩潰surrogateescape錯誤策略,但它需要轉換測試[binary] -> [str] -> [binary]來驗證性能和可靠性。

UPDATE 20170116 :感謝Nearoo的評論 - 也有可能使用backslashreplace錯誤處理程序將所有未知字節跳過。 這僅適用於Python 3,所以即使使用此解決方法,仍然會從不同的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'))

有關詳細信息,請參閱https://docs.python.org/3/howto/unicode.html#python-s-unicode-support

UPDATE 20170119 :我決定實施適用於Python 2和Python 3的斜線轉義解碼。它應該比cp437解決方案慢,但它應該在每個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'))



http://docs.python.org/3/library/sys.html

要向標準流寫入或讀取二進制數據,請使用基礎二進制緩衝區。 例如,要將字節寫入標準輸出,請使用sys.stdout.buffer.write(b'abc')。




對於Python 3,這是一個更安全的Pythonic方法來從byte轉換為string

def byte_to_str(bytes_or_str):
    if isinstance(bytes_or_str, bytes): #check if its 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')

輸出:

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



Related