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

Posted

技术标签:

【中文标题】如何从 Python 3 中的字节数组中的特定位中提取值?【英文标题】:How to extract a value from specific bits from a byte array in Python 3? 【发布时间】:2021-10-31 23:23:15 【问题描述】:

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

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

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

如果我想要位 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 中遇到了问题。这些是我认为我应该做的步骤,但我不确定这是否是最好/最简单的方法,也不知道我应该如何做......

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

...所以...

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

...我的思考过程在这方面有什么好处吗,或者有更简单的方法来完成这个吗?

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

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

【问题讨论】:

所以你想丢弃 2 MSB 并合并?所以00110010 00100001 变成了110010100001?你熟悉按位运算符吗? 是的,我很熟悉它们。我的问题是我需要先提取这些位,然后才能将它们转换为数字。提取这些位之后,我失去了关于它们在被提取之前所持有的位置的参考,所以我不知道要忽略哪些位。 我应该注意,我在上面的示例中插入了空格以提高可读性。这些空格不会存在于脚本使用的实际数据中。 我想我不理解目标。你如何从00110010 00100001 得到1185?如果您删除每个数字中的 2 个最高有效位,您将得到 110010 100001。如果你加入那些你得到 3233。 【参考方案1】:

这是你要找的吗?

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'

【讨论】:

我已经更新了我的问题中的示例,以包含我必须开始的字节数组。我需要做的是提取一个由该字节数组中的一部分位组成的值。我使用的数据最初是用六位字符格式编码的,所以第七位和第八位永远不会有数据,应该被忽略,但它们存在于我的八位数据流中。【参考方案2】:

这就是我想出的......

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 

【讨论】:

我不认为这个解决方案会提供正确的输出:1. 切片顺序不正确,它会产生一个空字符串,2.我>The high two bits do not contain data, but they should be counted...。您首先使用replace 清理这些位,这样它们就不会被计算在内,因此,您将添加/包含更多位。 我认为我的第 3 步和第 4 步在我的问题中的顺序错误。我已编辑问题以更正我的要求。【参考方案3】:

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

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

【讨论】:

以上是关于如何从 Python 3 中的字节数组中的特定位中提取值?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Python 3 中从字节缓冲区构造内存中的 TarFile 对象?

Python:如何从 4 字节字节数组中获取 4 字节大小的整数?

如何从 micropython 中的字节数组/字节转换?

如何从Java中的字节数组中获取数据?

h5py 可以从内存中的字节数组加载文件吗?

如何以字节数组从服务器中的文件中读取数据