首页 文章

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

提问于
浏览
131

如何在python中将字符串转换为int?

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

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

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

我知道必须有内置或标准库中的内容,这样做更简单...

这与converting a string of hex digits不同,你可以使用int(xxx,16),但我想转换一串实际的字节值 .

更新:

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

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

我的hacky方法:

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

包括导入模块的成本几乎抵消了该方法的所有优点 . 我相信这只会包括在整个基准测试中导入一次的费用;看看我每次强迫它重装时会发生什么:

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

毋庸置疑,如果你在每次导入时执行大量的这种方法,那么这个问题就会成比例地减少 . 它也可能是i / o成本而不是cpu,因此它可能取决于特定机器的容量和负载特性 .

10 回答

  • 62

    您也可以使用struct模块执行此操作:

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

    在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
    

    根据你的字节串的endianness .

    这也适用于任意长度的bytestring-integers,以及通过指定 signed=True 的二进制补码有符号整数 . 见docs for from_bytes .

  • 93

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

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

    ......这跟:

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

    ...除了它可以用于任何数量的字节 .

  • 6

    我使用以下函数在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

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

    警告:以上内容特别针对特定于平台 . “I”说明符和string-> int转换的字节顺序都取决于您的特定Python实现 . 但是如果你想一次转换很多整数/字符串,那么数组模块就可以快速完成 .

  • 1

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

  • 7

    如果您的版本> = 3.2,则int.from_bytes是最佳解决方案 . “struct.unpack”解决方案需要一个字符串,因此它不适用于字节数组 . 这是另一个解决方案:

    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个字节

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

    测试1:逆:

    >>> hex(2043455163)
    '0x79cca6bb'
    

    测试2:字节数> 8:

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

    测试3:增加一:

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

    测试4:附加一个字节,说'A':

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

    测试5:除以256:

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

    正如预期的那样,结果等于测试4的结果 .

  • 1

    如上所述使用 unpack 函数 struct 是个好方法 . 如果您想实现自己的功能,还有另一种解决方案:

    def bytes_to_int(bytes):
        result = 0
        for b in bytes:
            result = result * 256 + int(b)
    return result
    
  • 5

    我正在努力寻找可在Python 2.x下工作的任意长度字节序列的解决方案 . 最后我写了这个,它有点hacky因为它执行字符串转换,但它的工作原理 .

    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)
    

    此功能有两个要求:

    • 输入 data 需要是 bytearray . 您可以像这样调用函数:
    s = 'y\xcc\xa6\xbb'
    n = signedbytes(s)
    
    • 数据需要是大端的 . 如果你有一个小端值,你应该先反转它:
    n = signedbytes(s[::-1])
    

    当然,只有在需要任意长度时才应该使用它 . 否则,坚持使用更多标准方式(例如 struct ) .

相关问题