web-dev-qa-db-fra.com

Python: extraire des bits d'un octet

Je lis un fichier binaire en python et la documentation pour le format de fichier dit:

Drapeau (en binaire) Signification

1 nnn nnnn Indique qu'il y a un octet de données à suivre qui doit être dupliqué nnn nnnn (127 maximum) fois.

0 nnn nnnn Indique qu'il y a nnn nnnn octets de données d'image à suivre (127 octets maximum) et qu'il n'y a pas de duplication.

n 000 0000 Champ de fin de ligne. Indique la fin d'un enregistrement de ligne. La valeur de n peut être zéro ou un. Notez que le champ de fin de ligne est obligatoire et qu'il se reflète dans la longueur du champ d'enregistrement de ligne mentionné ci-dessus.

En lisant le fichier, je m'attends à l'octet auquel je dois retourner 1 nnn nnnn où le nnn nnnn la partie doit avoir 50 ans.

J'ai pu le faire en utilisant les éléments suivants:

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

Mais le calcul des chiffres semble être une solution de contournement bon marché.

Puis-je faire plus de calculs binaires pour effectuer le calcul des nombres?

Comment aborderiez-vous cela?

21
Evan Borgstrom

Vous pouvez supprimer le bit de tête à l'aide d'un masque ET avec un octet du fichier. Cela vous laissera la valeur des bits restants:

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

Je trouve les nombres binaires plus faciles à comprendre que hexadécimal lors du masquage de bits.

EDIT: Exemple légèrement plus complet pour votre cas d'utilisation:

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
12
alan

L'approche classique pour vérifier si un bit est défini est d'utiliser l'opérateur binaire "et", c'est-à-dire.

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

Pour vérifier si le n ^ ème bit est défini, utilisez la puissance de deux ou mieux le décalage de bits

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
16
Zaur Nasibov

Si j'ai bien lu votre description:

if (byte & 0x80) != 0:
    num_bytes = byte & 0x7F
1
D.Shawley

Vous pouvez le faire comme ceci:

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)
0
bgporter

voilà:

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
0
K.-Michael Aye

Au lieu de int (bin (octet) [3:], 2), vous pouvez simplement utiliser: int (bin (octet >> 1), 2)

0
theonova

je ne sais pas si je vous ai bien compris, mais si je le faisais, cela devrait faire l'affaire:

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