簡體   English   中英

在 Python 3 中將二進制字符串轉換為 bytearray

[英]Convert binary string to bytearray in Python 3

盡管有許多相關的問題,但我找不到與我的問題相符的問題。 我想將二進制字符串(例如, "0110100001101001" )更改為字節數組(相同的示例, b"hi" )。

我試過這個:

bytes([int(i) for i in "0110100001101001"])

但我得到了:

b'\x00\x01\x01\x00\x01' #... and so on

在 Python 3 中執行此操作的正確方法是什么?

這是按照 Patrick 提到的第一種方式進行操作的示例:將位串轉換為 int 並一次取 8 位。 這樣做的自然方法是以相反的順序生成字節。 為了將字節恢復到正確的順序,我在字節數組上使用擴展切片符號,步長為 -1: b[::-1]

def bitstring_to_bytes(s):
    v = int(s, 2)
    b = bytearray()
    while v:
        b.append(v & 0xff)
        v >>= 8
    return bytes(b[::-1])

s = "0110100001101001"
print(bitstring_to_bytes(s))

顯然,Patrick 的第二種方式更加緊湊。 :)

但是,在 Python 3 中有更好的方法來做到這一點:使用int.to_bytes方法:

def bitstring_to_bytes(s):
    return int(s, 2).to_bytes((len(s) + 7) // 8, byteorder='big')

如果len(s)保證是 8 的倍數,那么.to_bytes的第一個 arg 可以簡化:

return int(s, 2).to_bytes(len(s) // 8, byteorder='big')

如果len(s)不是8 的倍數,這將引發OverflowError ,這在某些情況下可能是可取的。


另一種選擇是使用雙重否定來執行天花板划分。 對於整數 a 和 b,使用//地板除法

n = a // b

給出整數 n 使得
n <= a/b < n + 1
例如,
47 // 10給出 4,並且

-47 // 10給出 -5。 所以

-(-47 // 10)給出 5,有效地執行天花板划分。

因此在bitstring_to_bytes我們可以這樣做:

return int(s, 2).to_bytes(-(-len(s) // 8), byteorder='big')

然而,沒有多少人熟悉這種高效且緊湊的習語,因此通常認為它的可讀性不如

return (s, 2).to_bytes((len(s) + 7) // 8, byteorder='big')

您必須將其轉換為 int 並一次取 8 位,或者將其切成 8 字節長的字符串,然后將它們中的每一個都轉換為 int。 在 Python 3 中,正如 PM 2Ring 和 JF Sebastian 的回答所示, intto_bytes()方法允許您非常有效地執行第一種方法。 這在 Python 2 中不可用,因此對於堅持使用它的人來說,第二種方法可能更有效。 下面是一個例子:

>>> s = "0110100001101001"
>>> bytes(int(s[i : i + 8], 2) for i in range(0, len(s), 8))
b'hi'

分解一下,范圍語句從索引 0 開始,並為我們提供源字符串的索引,但一次推進 8 個索引。 由於s有 16 個字符長,它將為我們提供兩個索引:

>>> list(range(0, 50, 8))
[0, 8, 16, 24, 32, 40, 48]
>>> list(range(0, len(s), 8))
[0, 8]

(我們在這里使用list()來顯示將從 Python 3 中的范圍迭代器中檢索的值。)

然后我們可以在此基礎上通過取 8 個字符長的切片來拆分字符串:

>>> [s[i : i + 8] for i in range(0, len(s), 8)]
['01101000', '01101001']

然后我們可以將它們中的每一個轉換為整數,基數為 2:

>>> list(int(s[i : i + 8], 2) for i in range(0, len(s), 8))
[104, 105]

最后,我們將整個內容包裝在bytes()以獲得答案:

>>> bytes(int(s[i : i + 8], 2) for i in range(0, len(s), 8))
b'hi'
>>> zero_one_string = "0110100001101001"
>>> int(zero_one_string, 2).to_bytes((len(zero_one_string) + 7) // 8, 'big')
b'hi'

它返回bytes對象,它是一個不可變的字節序列。 如果你想獲得一個bytearray -字節的可變序列-然后就調用bytearray(b'hi')

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM