簡體   English   中英

將字符串轉換為位列表,反之亦然

[英]Convert string to list of bits and viceversa

我需要將ASCII字符串轉換為位列表,反之亦然:

str = "Hi" -> [0,1,0,0,1,0,0,0,0,1,1,0,1,0,0,1]

[0,1,0,0,1,0,0,0,0,1,1,0,1,0,0,1] -> "Hi"

使用庫函數可以有很多方法。 但是我偏愛第三方bitarray模塊。

>>> import bitarray
>>> ba = bitarray.bitarray()

從字符串轉換需要一些儀式。 曾幾何時,您可以只使用fromstring ,但是現在不贊成使用該方法,因為它必須將字符串隱式編碼為字節。 為了避免不可避免的編碼錯誤,最好將bytes對象傳遞給frombytes 從字符串開始時,這意味着您必須顯式指定編碼-無論如何都是一種好習慣。

>>> ba.frombytes('Hi'.encode('utf-8'))
>>> ba
bitarray('0100100001101001')

轉換為列表很容易。 (此外,位串對象已經具有很多類似列表的功能。)

>>> l = ba.tolist()
>>> l
[False, True, False, False, True, False, False, False, 
 False, True, True, False, True, False, False, True]

可以通過任何可迭代的方式創建bitstring

>>> bitarray.bitarray(l)
bitarray('0100100001101001')

轉換回字節或字符串也相對容易:

>>> bitarray.bitarray(l).tobytes().decode('utf-8')
'Hi'

為了純粹的娛樂:

>>> def s_to_bitlist(s):
...     ords = (ord(c) for c in s)
...     shifts = (7, 6, 5, 4, 3, 2, 1, 0)
...     return [(o >> shift) & 1 for o in ords for shift in shifts]
... 
>>> def bitlist_to_chars(bl):
...     bi = iter(bl)
...     bytes = zip(*(bi,) * 8)
...     shifts = (7, 6, 5, 4, 3, 2, 1, 0)
...     for byte in bytes:
...         yield chr(sum(bit << s for bit, s in zip(byte, shifts)))
... 
>>> def bitlist_to_s(bl):
...     return ''.join(bitlist_to_chars(bl))
... 
>>> s_to_bitlist('Hi')
[0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1]
>>> bitlist_to_s(s_to_bitlist('Hi'))
'Hi'

可能有更快的方法來執行此操作,但不使用其他模塊:

def tobits(s):
    result = []
    for c in s:
        bits = bin(ord(c))[2:]
        bits = '00000000'[len(bits):] + bits
        result.extend([int(b) for b in bits])
    return result

def frombits(bits):
    chars = []
    for b in range(len(bits) / 8):
        byte = bits[b*8:(b+1)*8]
        chars.append(chr(int(''.join([str(bit) for bit in byte]), 2)))
    return ''.join(chars)

不知道為什么,但是這里有兩個僅使用內置函數的丑陋的oneliner:

s = "Hi"
l = map(int, ''.join([bin(ord(i)).lstrip('0b').rjust(8,'0') for i in s]))
s = "".join(chr(int("".join(map(str,l[i:i+8])),2)) for i in range(0,len(l),8))

產量:

>>> l
[0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1]
>>> s
'Hi'

在實際代碼中,請使用structbitarray模塊。

def text_to_bits(text):
    """
    >>> text_to_bits("Hi")
    [0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1]
    """
    bits = bin(int.from_bytes(text.encode(), 'big'))[2:]
    return list(map(int, bits.zfill(8 * ((len(bits) + 7) // 8))))

def text_from_bits(bits):
    """
    >>> text_from_bits([0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1])
    'Hi'
    """
    n = int(''.join(map(str, bits)), 2)
    return n.to_bytes((n.bit_length() + 7) // 8, 'big').decode()

另請參見將二進制轉換為ASCII,反之亦然(Python)

您可以使用內置的bytearray

>>> for i in bytearray('Hi', 'ascii'):
...     print(i)
... 
72
105

>>> bytearray([72, 105]).decode('ascii')
'Hi'

bin()轉換為二進制。

一些速度比較。 這些都使用

python -m timeit "code"

要么

cat <<-EOF | python -m timeit
    code
EOF

如果是多行。

位到字節

A :1億次循環,最好為3:每循環0.00838微秒

res = 0
for idx,x in enumerate([0,0,1,0,1,0,0,1]):
    res |= (x << idx)

B :1億次循環,最好為3:每循環0.00838微秒

int(''.join(map(str, [0,0,1,0,1,0,0,1])), 2)

字節到位

A :1億次循環,最好為3:每循環0.00836微秒

[(41 >> x) & 1 for x in range(7, -1, -1)]

B :100000次循環,最好為3:每個循環2.07微秒

map(int, bin(41)[2:])
def to_bin(string):
    res = ''
    for char in string:
        tmp = bin(ord(char))[2:]
        tmp = '%08d' %int(tmp)
        res += tmp
    return res

def to_str(string):
    res = ''
    for idx in range(len(string)/8):
        tmp = chr(int(string[idx*8:(idx+1)*8], 2))
        res += tmp
    return res

這些功能真的很簡單。
它不使用第三方模塊。

import math

class BitList:
    def __init__(self, value):
        if isinstance(value, str):
            value = sum([bytearray(value, "utf-8")[-i - 1] << (8*i) for i in range(len(bytearray(value, "utf-8")))])
        try:
            self.value = sum([value[-i - 1] << i for i in range(len(value))])
        except Exception:
            self.value = value

    def __getitem__(self, index):
        if isinstance(index, slice):
            if index.step != None and index.step != 1:
                return list(self)[index]
            else:
                start = index.start if index.start else 0
                stop = index.stop if index.stop != None else len(self)

                return BitList(math.floor((self.value % (2 ** (len(self) - start))) >> (len(self) - stop)))
        else:
            return bool(self[index:index + 1].value)

    def __len__(self):
        return math.ceil(math.log2(self.value + 1))

    def __str__(self):
        return self.value

    def __repr__(self):
        return "BitList(" + str(self.value) + ")"

    def __iter__(self):
        yield from [self[i] for i in range(len(self))]

然后,您可以使用數字或列表(數字或布爾值)初始化BitList ,然后獲取其值,獲取位置項,獲取切片並將其轉換為列表。 注意:當前無法設置項目,但是添加后我將編輯此帖子。

我以自己為己任,然后去尋找如何將字符串 (或文件)轉換為位列表,然后從另一個答案中找出答案。

這可能有效,但是如果您詢問PEP 8(長線,復雜),則無效

tobits = lambda x: "".join(map(lambda y:'00000000'[len(bin(ord(y))[2:]):]+bin(ord(y))[2:],x))
frombits = lambda x: ''.join([chr(int(str(y), 2)) for y in [x[y:y+8] for y in range(0,len(x),8)]])

這些功能與常規功能相同。

因為我喜歡發電機,所以將其發布在這里:

def bits(s):
    for c in s:
        yield from (int(bit) for bit in bin(ord(c))[2:].zfill(8))


def from_bits(b):
    for i in range(0, len(b), 8): 
        yield chr(int(''.join(str(bit) for bit in b[i:i + 8]), 2)) 


print(list(bits('Hi')))
[0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1]
print(''.join(from_bits([0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1])))
Hi

如果list有位,則只需將其轉換為str ,然后轉換為數字。 數字的行為類似於位字符串,然后可以應用按位運算。 例如 :

int(str([1,0,0,1]) | int(str([1,0,1,1])

暫無
暫無

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

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