from_bytes - convertir una cadena de bytes en un int(python)
string replace python 3 (10)
¿Cómo puedo convertir una cadena de bytes en un int en python?
Di así: ''y/xcc/xa6/xbb''
Se me ocurrió una manera inteligente / estúpida de hacerlo:
sum(ord(c) << (i * 8) for i, c in enumerate(''y/xcc/xa6/xbb''[::-1]))
Sé que tiene que haber algo incorporado o en la biblioteca estándar que hace esto más simplemente ...
Esto es diferente de convertir una cadena de dígitos hexadecimales para los que puede usar int (xxx, 16), pero en su lugar quiero convertir una cadena de valores de bytes reales.
ACTUALIZAR:
Me gusta más la respuesta de James porque no requiere importar otro módulo, pero el método de Greg es más rápido:
>>> from timeit import Timer
>>> Timer(''struct.unpack("<L", "y/xcc/xa6/xbb")[0]'', ''import struct'').timeit()
0.36242198944091797
>>> Timer("int(''y/xcc/xa6/xbb''.encode(''hex''), 16)").timeit()
1.1432669162750244
Mi método hacky:
>>> Timer("sum(ord(c) << (i * 8) for i, c in enumerate(''y/xcc/xa6/xbb''[::-1]))").timeit()
2.8819329738616943
ACTUALIZACIÓN ADICIONAL:
Alguien preguntó en comentarios cuál es el problema con la importación de otro módulo. Bueno, importar un módulo no es necesariamente barato, eche un vistazo:
>>> Timer("""import struct/nstruct.unpack(">L", "y/xcc/xa6/xbb")[0]""").timeit()
0.98822188377380371
Incluir el costo de importar el módulo anula casi todas las ventajas que tiene este método. Creo que esto solo incluirá el gasto de importarlo una vez para la ejecución de referencia completa; mira lo que pasa cuando lo obligo a recargar todo el tiempo:
>>> Timer("""reload(struct)/nstruct.unpack(">L", "y/xcc/xa6/xbb")[0]""", ''import struct'').timeit()
68.474128007888794
Huelga decir que si realiza muchas ejecuciones de este método por cada importación, esto se convierte en un problema proporcionalmente menor. También es probable que tenga un costo de I / O en lugar de una CPU, por lo que puede depender de la capacidad y las características de carga de la máquina en particular.
Como dijo Greg, puedes usar struct si estás tratando con valores binarios, pero si solo tienes un "número hexadecimal" pero en formato de bytes, tal vez quieras convertirlo así:
s = ''y/xcc/xa6/xbb''
num = int(s.encode(''hex''), 16)
... esto es lo mismo que:
num = struct.unpack(">L", s)[0]
... excepto que funcionará para cualquier cantidad de bytes.
Como se mencionó anteriormente, usar la función unpack
de struct es una buena manera. Si desea implementar su propia función, hay otra solución:
def bytes_to_int(bytes):
result = 0
for b in bytes:
result = result * 256 + int(b)
return result
En Python 2.x, puede usar los especificadores de formato <B
para bytes sin firmar, y <b
para bytes firmados con struct.unpack
/ struct.pack
.
P.ej:
Deje x
= ''/xff/x10/x11''
data_ints = struct.unpack(''<'' + ''B''*len(x), x) # [255, 16, 17]
Y:
data_bytes = struct.pack(''<'' + ''B''*len(data_ints), *data_ints) # ''/xff/x10/x11''
Eso *
es requerido!
Consulte para obtener una lista de los especificadores de formato.
En Python 3.2 y posterior, use
>>> int.from_bytes(b''y/xcc/xa6/xbb'', byteorder=''big'')
2043455163
o
>>> int.from_bytes(b''y/xcc/xa6/xbb'', byteorder=''little'')
3148270713
de acuerdo con la endianness de tu cadena de bytes.
Esto también funciona para bytes-enteros de longitud arbitraria, y para enteros con signo de complemento de dos especificando signed=True
. Ver los documentos para from_bytes
.
Estaba luchando por encontrar una solución para secuencias de bytes de longitud arbitraria que funcionaría en Python 2.x. Finalmente escribí este, es un poco hacky porque realiza una conversión de cadena, pero funciona.
Función para Python 2.x, longitud arbitraria
def signedbytes(data):
"""Convert a bytearray into an integer, considering the first bit as
sign. The data must be big-endian."""
negative = data[0] & 0x80 > 0
if negative:
inverted = bytearray(~d % 256 for d in data)
return -signedbytes(inverted) - 1
encoded = str(data).encode(''hex'')
return int(encoded, 16)
Esta función tiene dos requisitos:
Los
data
entrada deben ser unbytearray
. Puede llamar a la función de esta manera:s = ''y/xcc/xa6/xbb'' n = signedbytes(s)
La información debe ser big-endian. En caso de que tengas un valor little-endian, primero debes invertirlo:
n = signedbytes(s[::-1])
Por supuesto, esto debería usarse solo si se necesita una longitud arbitraria. De lo contrario, quédese con más formas estándar (por ejemplo, struct
).
También puede usar el módulo struct para hacer esto:
>>> struct.unpack("<L", "y/xcc/xa6/xbb")[0]
3148270713L
Utilizo la siguiente función para convertir datos entre int, hex y bytes.
def bytes2int(str):
return int(str.encode(''hex''), 16)
def bytes2hex(str):
return ''0x''+str.encode(''hex'')
def int2bytes(i):
h = int2hex(i)
return hex2bytes(h)
def int2hex(i):
return hex(i)
def hex2int(h):
if len(h) > 1 and h[0:2] == ''0x'':
h = h[2:]
if len(h) % 2:
h = "0" + h
return int(h, 16)
def hex2bytes(h):
if len(h) > 1 and h[0:2] == ''0x'':
h = h[2:]
if len(h) % 2:
h = "0" + h
return h.decode(''hex'')
Fuente: http://opentechnotes.blogspot.com.au/2014/04/convert-values-to-from-integer-hex.html
int.from_bytes es la mejor solución si estás en la versión> = 3.2. La solución "struct.unpack" requiere una cadena para que no se aplique a las matrices de bytes. Aquí hay otra solución:
def bytes2int( tb, order=''big''):
if order == ''big'': seq=[0,1,2,3]
elif order == ''little'': seq=[3,2,1,0]
i = 0
for j in seq: i = (i<<8)+tb[j]
return i
hex (bytes2int ([0x87, 0x65, 0x43, 0x21])) devuelve ''0x87654321''.
Maneja endianness grande y pequeño y es fácilmente modificable para 8 bytes
>>> reduce(lambda s, x: s*256 + x, bytearray("y/xcc/xa6/xbb"))
2043455163
Prueba 1: inversa
>>> hex(2043455163)
''0x79cca6bb''
Prueba 2: Número de bytes> 8:
>>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAAA"))
338822822454978555838225329091068225L
Prueba 3: Incrementar en uno:
>>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAAB"))
338822822454978555838225329091068226L
Prueba 4: añada un byte, diga ''A'':
>>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAABA"))
86738642548474510294585684247313465921L
Prueba 5: Divide por 256:
>>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAABA"))/256
338822822454978555838225329091068226L
El resultado es igual al resultado de la Prueba 4, como se esperaba.
import array
integerValue = array.array("I", ''y/xcc/xa6/xbb'')[0]
Advertencia: lo anterior es fuertemente específico de la plataforma. Tanto el especificador "I" como la endianidad de la conversión string-> int dependen de su implementación específica de Python. Pero si quiere convertir muchos enteros / cadenas a la vez, entonces el módulo de matriz lo hace rápidamente.