2011-12-14 10 views
5

tengo un byte (de algún otro proveedor), donde las máscaras potenciales bits son los siguientes:bit de marca en Python

valor1 = 0x01 valor2 = 0x02 valor3 = 0x03 valor4 = 0x04 valor5 = 0x05 value6 = 0x06 value7 = 0x40 value8 = 0x80

Puedo contar con UNO de value1 a value6 presente. Y luego value7 puede o no establecerse. value8 puede o no establecerse.

Esto es legal: valor2 | valor7 | valor8 Esto no es legal: valor1 | valor3 | valor7

Necesito averiguar si el valor 7 está establecido, el valor8 está establecido y cuál es el valor restante.

Tengo el siguiente código python. ¿Hay una manera más elegante de hacer esto?

value1 = 0x01 
value2 = 0x02 
value3 = 0x03 
value4 = 0x04 
value5 = 0x05 
value6 = 0x06 
value7 = 0x40 
value8 = 0x80 

def format_byte_as_bits(value): 
    return format(value,'b').zfill(8) 

def mask_bits_on_byte(byte,mask): 
    inverse_of_mask = mask^0b11111111 
    return byte & inverse_of_mask 

def parse_byte(byte): 

    value7_set = byte & value7 == value7 
    value8_set = byte & value8 == value8 
    byte = mask_bits_on_byte(byte,value7) 
    byte = mask_bits_on_byte(byte,value8) 
    base_value = byte 
    return value7_set,value8_set,base_value 

# Example 1 
byte = value3 | value7 
value7_set,value8_set,base_value = parse_byte(byte) 
print("base_value = "+str(base_value)) 
print("value7_set = "+str(value7_set)) 
print("value8_set = "+str(value8_set)) 
print() 

# Output: 
# base_value = 3 
# value7_set = True 
# value8_set = False 

# Example 2 
byte = value5 
value7_set,value8_set,base_value = parse_byte(byte) 
print("base_value = "+str(base_value)) 
print("value7_set = "+str(value7_set)) 
print("value8_set = "+str(value8_set)) 
print() 

# Output: 
# base_value = 5 
# value7_set = False 
# value8_set = False 

# Example 3 
byte = value1 | value7 | value8 
value7_set,value8_set,base_value = parse_byte(byte) 
print("base_value = "+str(base_value)) 
print("value7_set = "+str(value7_set)) 
print("value8_set = "+str(value8_set)) 

# Output: 
# base_value = 1 
# value7_set = True 
# value8_set = True 

EDIT - I LOVE stackoverflow. Tantas respuestas útiles, ¡tan rápido! Ustedes son increíbles! Ojalá pudiera marcar todas las respuestas. ¡Pero al menos les daré a todos un voto!

Edit2 - Sobre la base de las respuestas a continuación, el código se simplifica a la siguiente:

value1 = 0x01 
value2 = 0x02 
value3 = 0x03 
value4 = 0x04 
value5 = 0x05 
value6 = 0x06 
value7 = 0x40 
value8 = 0x80 

def parse_byte(byte): 
    return byte & value7, byte & 0x80, byte & 7 

# Example 1 
byte = value3 | value7 
value7_set,value8_set,base_value = parse_byte(byte) 
print("base_value = "+str(base_value)) 
if value7_set: print("value7_set") 
if value8_set: print("value8_set") 
print() 

# Example 2 
byte = value5 
value7_set,value8_set,base_value = parse_byte(byte) 
print("base_value = "+str(base_value)) 
if value7_set: print("value7_set") 
if value8_set: print("value8_set") 
print() 

# Example 3 
byte = value1 | value7 | value8 
value7_set,value8_set,base_value = parse_byte(byte) 
print("base_value = "+str(base_value)) 
if value7_set: print("value7_set") 
if value8_set: print("value8_set") 
print() 

Respuesta

10

La mayor parte de sus value* constantes no son en realidad bit máscaras, solamente value7 y value8 son. Me definir otra máscara de bits para extraer los bits más bajos, por lo que tendría máscaras de tres bits en total:

mask0 = 0x07 
mask1 = 0x40 
mask2 = 0x80 

Ahora su función se convierte en

def parse_byte(byte): 
    return byte & mask2, byte & mask1, byte & mask0 

que no convirtió a los resultados bool - - No veo por qué esto debería ser necesario. Al verificar el valor devuelto con if, se convertirá implícitamente en bool de todos modos.

También tenga en cuenta que

format(value,'b').zfill(8) 

se puede simplificar a

format(value,'08b') 
+0

Muy sucinto y aprecio el consejo sobre el zfill también. Utilizo el formato (valor, 'b'). Zfill (8) en todo el lugar, ahora puedo usar el formato (valor, '08b'). ¡Gracias por su respuesta! –

+1

Como un lado, una forma fácil de hacer máscaras de bits con un buen código legible es escribirlas como 'value1 = 1 << 0',' value2 = 1 << 1' (etc). Es decir, tome un solo bit y simplemente cambie el cambio. Los errores son más obvios que con los literales hexadecimales o decimales. Si la máscara necesita varios bits, solo '|' los une (por ejemplo, 'value3 = (1 << 2) | (1 << 3)' en lugar de 'value3 = 0x0c'). – Kat

3

No es necesario que los otros dos funciones:

def parse_byte(byte): 
    value7_set = byte & value7 == value7 
    value8_set = byte & value8 == value8 
    base_value = byte & 7 
    return value7_set,value8_set,base_value 
+0

Gracias! No pensé en el byte y 7. –

1

Es un poco prolijo, pero perfectamente multa. El único cambio que me gustaría hacer es simplificar parse_byte:

def parse_byte(byte): 

    value7_set = byte & value7 == value7 
    value8_set = byte & value8 == value8 
    base_value = mask_bits_on_byte(byte,value7 | value8) 
    return value7_set,value8_set,base_value 
+0

¡Gracias por su respuesta! –

4

Dado un valor tales como:

>>> x = 0b10001000 

Puede averiguar si los bits superiores se fijan con:

>>> bit8 = bool(x & 0b10000000) 
>>> bit7 = bool(x & 0b01000000) 

para encontrar qué bits inferior se establece, usar un diccionario:

>>> bdict = dict((1<<i, i+1) for i in range(6)) 
>>> bdict[x & 0b00111111] 
4 
+0

¡Gracias por su respuesta! –

+0

@MatthewLund Feliz de ser de ayuda :-) –