【问题标题】:Python: Extracting bits from a bytePython:从字节中提取位
【发布时间】:2012-04-14 07:13:00
【问题描述】:

我正在用 python 读取一个二进制文件,文件格式的文档说:

标志(二进制)含义

1 nnn nnnn 表示后面有一个数据字节 这是要复制的 nnn nnnn(最多 127 个) 次。

0 nnn nnnn 表示图像有 nnn nnnn 字节 接下来的数据(最大 127 字节)和 没有重复。

n 000 0000 行尾字段。表示一行的结束 记录。 n 的值可以是零或一。 请注意,行尾字段是必需的,并且 它反映在行记录的长度上 上面提到的字段。

在读取文件时,我希望我所在的字节返回 1 nnn nnnn,其中 nnn nnnn 部分应该是 50。

我已经能够使用以下方法做到这一点:

flag = byte >> 7
numbytes = int(bin(byte)[3:], 2)

但 numbytes 计算感觉像是一种廉价的解决方法。

我可以做更多的位数学来完成 numbytes 的计算吗?

你会如何处理这个问题?

【问题讨论】:

标签: python byte bit


【解决方案1】:

检查一个位是否被设置的经典方法是使用二进制“与”运算符,即

x = 10 # 1010 in binary
if x & 0b10:  # explicitly: x & 0b0010 != 0
    print('First bit is set')

要检查是否设置了第 n^ 位,请使用 2 的幂或更好的位移

def is_set(x, n):
    return x & 2 ** n != 0 

    # a more bitwise- and performance-friendly version:
    return x & 1 << n != 0

is_set(10, 1) # 1 i.e. first bit - as the count starts at 0-th bit
>>> True

【讨论】:

  • 谢谢,但这并不能真正回答我的问题。给定 byte = 178,你将如何提取 flag == 1 & numbytes == 50?
  • +1:但不需要 !=0 部分,if x&amp;0b10 就足够了。
  • != 0 不如== True 糟糕,但也差不多。 :)
  • Explicit is better than implicit 所以x &amp; 0b10 != 0 对我来说很好
  • 考虑一下:bin(178) == 10110010;如果我理解正确,您需要返回从第 5 个字节开始的所有字节。然后 178 & (2^5 - 1) 应该可以解决问题,因为在这种情况下 10110010 & 00011111 == 00010010
【解决方案2】:

您可以使用掩码与文件中的字节进行“与”运算来去除前导位。这将为您留下剩余位的值:

mask =  0b01111111
byte_from_file = 0b10101010
value = mask & byte_from_file
print bin(value)
>> 0b101010
print value
>> 42

在进行位掩码时,我发现二进制数比十六进制数更容易理解。

编辑:为您的用例提供更完整的示例:

LEADING_BIT_MASK =  0b10000000
VALUE_MASK = 0b01111111

values = [0b10101010, 0b01010101, 0b0000000, 0b10000000]

for v in values:
    value = v & VALUE_MASK
    has_leading_bit = v & LEADING_BIT_MASK
    if value == 0:
        print "EOL"
    elif has_leading_bit:
        print "leading one", value
    elif not has_leading_bit:
        print "leading zero", value

【讨论】:

  • 谢谢。在这种情况下,我也更喜欢二进制数。
  • @EvanBorgstrom 在 Python 3 上,您可以编写:data = b'\xaa\x55\x00\x80'for byte in data: ...。不要使用bytes 名称,它是一个内置类型。
【解决方案3】:

如果我没看错你的描述:

if (byte & 0x80) != 0:
    num_bytes = byte & 0x7F

【讨论】:

    【解决方案4】:

    你去吧:

    class ControlWord(object):
        """Helper class to deal with control words.
    
        Bit setting and checking methods are implemented.
        """
        def __init__(self, value = 0):
            self.value = int(value)
        def set_bit(self, bit):
            self.value |= bit
        def check_bit(self, bit):
            return self.value & bit != 0
        def clear_bit(self, bit):    
            self.value &= ~bit
    

    【讨论】:

      【解决方案5】:

      您可以简单地使用 int(bin(byte>>1),2) 来代替 int(bin(byte)[3:], 2)

      【讨论】:

        【解决方案6】:

        不确定我是否正确地理解了你,但如果我这样做了,这应该可以解决问题:

        >>> x = 154 #just an example
        >>> flag = x >> 1
        >>> flag
        1
        >>> nb = x & 127
        >>> nb
        26
        

        【讨论】:

          【解决方案7】:

          你可以这样做:

          def GetVal(b):
             # mask off the most significant bit, see if it's set
             flag = b & 0x80 == 0x80
             # then look at the lower 7 bits in the byte.
             count = b & 0x7f
             # return a tuple indicating the state of the high bit, and the 
             # remaining integer value without the high bit.
             return (flag, count)
          
          >>> testVal = 50 + 0x80
          >>> GetVal(testVal)
          (True, 50)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-03-02
            • 1970-01-01
            • 1970-01-01
            • 2020-11-04
            • 1970-01-01
            • 2015-04-14
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多