python - 將字節轉換為字符串?




7 Answers

你需要解碼bytes對象來產生一個字符串:

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

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

>>> 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一致。




您需要解碼字節字符串並將其轉換為字符(unicode)字符串。

b'hello'.decode(encoding)

要么

str(b'hello', encoding)



我認為你真正想要的是這樣的:

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

亞倫的回答是正確的,除了你需要知道使用哪種編碼。 我相信Windows使用'windows-1252'。 只有當你的內容中有一些不尋常的(非ascii)字符時,它才會起作用,但是它會起到重要作用。

順便說一句,它的重要性在於Python轉向使用兩種不同類型的二進制和文本數據的原因:它不能在它們之間神奇地轉換,因為它不知道編碼,除非你告訴它! 你知道的唯一方法是閱讀Windows文檔(或者在這裡閱讀)。




將universal_newlines設置為True,即

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



要將字節序列解釋為文本,您必須知道相應的字符編碼:

unicode_text = bytestring.decode(character_encoding)

例:

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

ls命令可能會產生不能被解釋為文本的輸出。 Unix上的文件名可以是除斜杠b'/'和零b'\0'外的任何字節序列:

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

嘗試使用utf-8編碼解碼這種字節湯會引發UnicodeDecodeError

它可能會更糟。 如果您使用錯誤的不兼容編碼,解碼可能會失敗並產生mojibake

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

數據已損壞,但您的程序仍不知道發生了故障。

通常,使用什麼字符編碼並不嵌入字節序列本身。 您必須在帶外傳達此信息。 一些結果比其他結果更可能存在,因此chardet模塊存在,可以猜測字符編碼。 一個Python腳本可能在不同的地方使用多個字符編碼。

使用os.fsdecode()函數可以將ls輸出轉換為Python字符串,即使對於不可解碼的文件名也是如此 (它在Unix上使用sys.getfilesystemencoding()surrogateescape錯誤處理程序):

import os
import subprocess

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

要獲得原始字節,可以使用os.fsencode()

如果您傳遞了universal_newlines=True參數,則subprocess locale.getpreferredencoding(False)使用locale.getpreferredencoding(False)來解碼字節,例如,它可以是Windows上的cp1252

要實時解碼字節流,可以使用io.TextIOWrapper() : example 。

不同的命令可能會為其輸出使用不同的字符編碼,例如, dir內部命令( cmd )可能使用cp437。 要解碼它的輸出,你可以顯式地傳遞編碼(Python 3.6+):

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

文件名可能與os.listdir() (它使用Windows Unicode API)不同,例如, '\xb6'可以用'\x14'替代--Python的cp437編解碼器映射b'\x14'來控製字符U + 0014而不是U + 00B6(¶)。 要支持具有任意Unicode字符的文件名,請參閱將可能包含非ASCII字符 Unicode字符的poweshell輸出解碼為python字符串




如果你應該通過嘗試decode()來獲得以下內容:

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

您還可以在演員中直接指定編碼類型:

>>> my_byte_str
b'Hello World'

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



在處理來自Windows系統的數據時(使用\r\n行尾),我的答案是

String = Bytes.decode("utf-8").replace("\r\n", "\n")

為什麼? 嘗試使用多行Input.txt:

Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8")
open("Output.txt", "w").write(String)

你所有的行結束都會加倍(到\r\r\n ),導致額外的空行。 Python的文本閱讀功能通常會標準化行尾,以便字符串僅使用\n 。 如果您從Windows系統收到二進制數據,Python沒有機會這樣做。 從而,

Bytes = open("Input.txt", "rb").read()
String = Bytes.decode("utf-8").replace("\r\n", "\n")
open("Output.txt", "w").write(String)

將復制您的原始文件。




Related