将一串字节转换为一个int(python)

如何将一个字节的string转换为Python中的int?

像这样说: 'y\xcc\xa6\xbb'

我想出了一个聪明/愚蠢的做法:

 sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1])) 

我知道必须有内置的东西,或在标准的库,这更简单地…

这不同于转换可以使用int(xxx,16) 的hex数字的string ,但是我想要转换一串实际的字节值。

更新:

我有点像詹姆斯的回答好一点,因为它不需要导入另一个模块,但格雷格的方法更快:

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

我的哈克法:

 >>> Timer("sum(ord(c) << (i * 8) for i, c in enumerate('y\xcc\xa6\xbb'[::-1]))").timeit() 2.8819329738616943 

进一步更新:

有人问道在导入另一个模块时会遇到什么问题。 那么导入一个模块不一定便宜,看看:

 >>> Timer("""import struct\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""").timeit() 0.98822188377380371 

包括导入模块的成本几乎否定了这种方法所具有的所有优点。 我相信这只会包括在整个基准testing期间import一次的费用; 看看我每次强制重新加载时会发生什么情况:

 >>> Timer("""reload(struct)\nstruct.unpack(">L", "y\xcc\xa6\xbb")[0]""", 'import struct').timeit() 68.474128007888794 

毋庸置疑,如果你对这个方法每进行一次执行很多次,那么这个问题的成功率就会小得多。 这也可能是I / O成本,而不是CPU,所以它可能取决于特定机器的容量和负载特性。

你也可以使用结构模块来做到这一点:

 >>> struct.unpack("<L", "y\xcc\xa6\xbb")[0] 3148270713L 

在Python 3.2及更高版本中,使用

 >>> int.from_bytes(b'y\xcc\xa6\xbb', byteorder='big') 2043455163 

要么

 >>> int.from_bytes(b'y\xcc\xa6\xbb', byteorder='little') 3148270713 

根据你的字节串的字节顺序 。

这也适用于任意长度的string整数,以及通过指定signed=True来表示两个补码有符号整数。 查看from_bytes的文档 。

正如Greg所说的,如果你正在处理二进制值,你可以使用struct,但是如果你只是有一个“hex数字”,但是以字节格式,你可能只想把它转换为:

 s = 'y\xcc\xa6\xbb' num = int(s.encode('hex'), 16) 

…这是一样的:

 num = struct.unpack(">L", s)[0] 

…除了它可以工作任何数量的字节。

 import array integerValue = array.array("I", 'y\xcc\xa6\xbb')[0] 

警告:以上是强烈平台特定的。 “I”说明符和string-> int转换的字节序都依赖于您的特定Python实现。 但是,如果您想要一次转换多个整数/string,那么arrays模块会快速执行。

我使用以下函数在int,hex和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') 

资料来源: http : //opentechnotes.blogspot.com.au/2014/04/convert-values-to-from-integer-hex.html

在Python 2.x中,可以使用格式说明符<B表示无符号字节, <b表示带有struct.unpack / struct.pack带符号字节。

例如:

x = '\xff\x10\x11'

data_ints = struct.unpack('<' + 'B'*len(x), x) # [255, 16, 17]

和:

data_bytes = struct.pack('<' + 'B'*len(data_ints), *data_ints) # '\xff\x10\x11'
*是必需的!

有关格式说明符的列表,请参阅https://docs.python.org/2/library/struct.html#format-characters

如果您的版本> = 3.2,int.from_bytes是最好的解决scheme。 “struct.unpack”解决scheme需要一个string,所以它不适用于字节数组。 这是另一个解决scheme:

 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]))返回“0x87654321”。

它处理大和小的字节顺序,可以容易地修改为8个字节

 >>> reduce(lambda s, x: s*256 + x, bytearray("y\xcc\xa6\xbb")) 2043455163 

testing1:反转:

 >>> hex(2043455163) '0x79cca6bb' 

testing2:字节数> 8:

 >>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAAA")) 338822822454978555838225329091068225L 

testing3:增加一个:

 >>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAAB")) 338822822454978555838225329091068226L 

testing4:追加一个字节,说'A':

 >>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAABA")) 86738642548474510294585684247313465921L 

testing5:除以256:

 >>> reduce(lambda s, x: s*256 + x, bytearray("AAAAAAAAAAAAAABA"))/256 338822822454978555838225329091068226L 

如预期的那样,结果等于testing4的结果。

我正在努力寻找一个可以在Python 2.x下工作的任意长度字节序列的解决scheme。 最后我写了这个,这有点不好意思,因为它执行string转换,但它的工作原理。

Python 2.x的函数,任意长度

 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) 

这个function有两个要求:

  • inputdata需要是一个bytearray 。 你可以这样调用函数:

     s = 'y\xcc\xa6\xbb' n = signedbytes(s) 
  • 数据需要是大端的。 如果你有一个little-endian的价值,你应该先倒过来:

     n = signedbytes(s[::-1]) 

当然,只有在需要任意长度的情况下才能使用。 否则,坚持更多的标准方式(如struct )。