如何从 Python 3 中的字节数组的特定位中提取值?

How to extract a value from specific bits from a byte array in Python 3?

我有一个长度为 6 个字节(48 位)的字节数组。只有每个字节的前六位是相关的。高两位不包含数据,因此应忽略。转换为数字时不应包含它们。

我想从字节数组中提取特定范围的位并将其转换为数字,同时忽略每个字节的高两位。

例如
以下面的字节数组为例:b'\x12\x08\x1c\x30\x32\x21'
位 47 -> 00010010 00001000 00011100 00110000 00110010 00100001 <- 位 0

如果我想要位 0 到 15 的值。答案应该是 3233(1+32+128+1024+2048)

00010010 00001000 00011100 00110000 00110010 00100001  
                               ^^^^ XX^^^^^^ XX^^^^^^  

       

如果我想要第 6 位到第 12 位的值。它应该是 50 (2+16+32)

00010010 00001000 00011100 00110000 00110010 00100001
                                  ^ XX^^^^^^ XX      

我可以在脑海中笨拙地做这件事,但我在 Python 中遇到问题。这些是我 认为 我应该做的步骤,但我不确定这是否是 best/easiest 方式,也不确定我应该如何做...

  1. 将我的字节数组转换为包含它的二进制值的单个字符串
  2. 将二进制字符串的每第七个和第八个字符(从右侧算起)更改为另一个字符(例如“-”)。
  3. 从新字符串中删除任何“-”字符。 [已编辑]
  4. 从二进制字符串中提取我想要的位。 [已编辑]
  5. 将该字符串从二进制转换为值。

...所以...

1。如何获取字节数组并将其转换为 48 位二进制字符串?
2.有没有一种简单的方法可以将我的二进制字符串中的每个第七和第八位更改为“-”?
5.将包含二进制值的字符串转换为数字?

...我的思考过程对此是否有用,或者是否有更简单的方法来完成此操作?

非常感谢您对此提供的帮助。

[edit] 我想我的问题中的第 3 步和第 4 步顺序错误......我想在提取二进制数字之前删除不需要的位。相应地编辑了问题。[/edit]

这是您要找的吗?

bytes6 = bytearray([0b00010010, 0b00001000, 0b00011100, 0b00110000, 0b00110010, 0b00100001])
shift = 30 # Shift first byte this much (6 bits * 5)
result = 0
for b in bytes6:
    result |= (b & 0x3F) << shift
    shift -= 6
print(bin(result))

输出:'0b10010001000011100110000110010100001'

这是我想出的...

def bit_value(data, first_bit, last_bit):
    """ Returns a value based on what bits are set between first_bit and last_bit of a byte array, ignoring bit 7 and 8 of each byte."""

    # Convert bytes to a binary string
    number = int.from_bytes(data, "big")
    bits = f"{number:048b}"

    # Change 7th and 8th bits to "-"
    clean_bits = ""
    for i in range(0,48):
        if i % 8 == 0 or i % 8 == 1:
            clean_bits += "-"
        else:
            clean_bits += bits[i]

    # Strip out the unwanted "-"
    clean_bits = clean_bits.replace("-","")

    # Get the bits we want
    bits_i_want = clean_bits[35-first_bit:36-last_bit]

    # Get the value of the resulting binary string
    value = int(bits_i_want, 2)

    return value 

如果我对你的要求理解正确,你可以试试这样:

test.py:

def bit_value(data, first_bit, last_bit):
    result = ""

    for i in range(47 - last_bit, 48 - first_bit):
        byte = i // 8
        bit = 7 - (i % 8)

        if bit < 6:
            result += "01"[data[byte] >> bit & 1]

    return int(result, 2)


def main():
    data = b"\x12\x08\x1c\x30\x32\x21"

    test1 = bit_value(data, 0, 15)
    print(f"{test1:#b}, {test1}")

    test2 = bit_value(data, 6, 12)
    print(f"{test2:#b}, {test2}")


if __name__ == "__main__":
    main()

测试:

$ python test.py 
0b110010100001, 3233
0b10010, 18