如何在Python中对比特流(而不是字节)进行编码是一个简单的模块吗?

2024-06-25 22:39:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我想把变量可数的位流编码和解码成二进制字符串数字64位编码字符串。流的最大长度约为21+20=41位,但可以稍长43、45。在

假设位将由某个数组表示。在

bits = [1]
encoded = someEncoder(bits)
decoded = someDecoder(encoded)
assert bits == decoded

比特流可以更长,例如:

^{pr2}$

考虑到它是变量位列表,编码/解码必须无损

a = someEncoder([0])
b = someEncoder([0, 0])
assert a != b

Tags: 字符串编码二进制数字数组assert解码bits
2条回答

根据@Martijn的回答,我想你需要以下内容。这使用编码前导1的思想来区分前导零的可变长度之间的差异:

import unittest
import itertools

def encode(bits):
    '''Encode n bits to an integer using a leading 1 to mark the length of the bit stream.

    Example: [0,0,0] == 0b1000 == 16
    '''
    # start with an initial 1.
    # iteratively shift current value left and OR in new bit.
    return reduce(lambda n,b: n << 1 | b,bits,1)

def decode(encoded):
    '''Decode a positive integer into a list of 0/1 values.
    The most significant bit marks the length and is removed.

    Example:  137 = 0b10001001 = [0,0,0,1,0,0,1]
    '''
    if encoded < 1:
        raise ValueError('encoded must be > 0')
    return [1 if c=='1' else 0 for c in format(encoded,'b')][1:]

class Cases(unittest.TestCase):
    def testEncodeZeros(self):
        for i in xrange(100):
            bits = [0]*i
            self.assertEqual(encode(bits),2**i)
    def testEncodeOnes(self):
        for i in xrange(100):
            bits = [1]*i
            self.assertEqual(encode(bits),2**(i+1)-1)
    def testDecodeZeros(self):
        for i in xrange(100):
            encoded = 2**i
            self.assertEqual(decode(encoded),[0]*i)
    def testDecodeOnes(self):
        for i in xrange(100):
            encoded = 2**(i+1)-1
            self.assertEqual(decode(encoded),[1]*i)
    def testEncodeDecode(self):
        for n in xrange(10):
            for bits in itertools.product([0,1],repeat=n):
                self.assertEqual(decode(encode(bits)),list(bits))
    def testDecodeZero(self):
        self.assertRaises(ValueError,decode,0)
    def testDecodeNegative(self):
        self.assertRaises(ValueError,decode,-1)

if __name__ == '__main__':
    unittest.main()

输出:

^{pr2}$

要将表示位的整数转换为8位字节(仍为整数),请使用位移位:

result = 0
for bit in bits:
    result = result << 1 | bit

或使用reduce()

^{pr2}$

这可以转换为一个二进制字符串,其中format(result, 'b'),可选地加上宽度和前缀0,以填充一定长度的零。在

演示:

>>> bits = [0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1]
>>> reduce(lambda n, b: n << 1 | b, bits)
934809
>>> result = 0
>>> for bit in bits:
...     result = result << 1 | bit
... 
>>> result
934809
>>> format(result, '021b')
'011100100001110011001'

如果需要直接转到二进制字符串,只需将位映射到字符串并连接:

>>> ''.join(map(str, bits))
'011100100001110011001'

可使用str.zfill()将其进一步填充到64个字符:

>>> ''.join(map(str, bits)).zfill(64)
'0000000000000000000000000000000000000000000011100100001110011001'

相关问题 更多 >