【问题标题】:reorder byte order in hex string (python)以十六进制字符串重新排序字节顺序(python)
【发布时间】:2012-10-20 18:30:15
【问题描述】:

我想在 python 中构建一个小型格式化程序,将数字返回给我 嵌入在十六进制字符串行中的值。

它是我的格式化程序的核心部分,应该可以合理快速地 格式化超过 100 行/秒(每行约 100 个字符)。

下面的代码应该给出一个我目前被阻止的例子。

'data_string_in_orig' 显示给定的输入格式。它一定要是 为每个字交换字节。从 'data_string_in_orig' 到 需要“data_string_in_swapped”。最后我需要结构 如图所示访问。预期结果在评论中。

提前致谢 沃尔夫冈R

#!/usr/bin/python

import binascii
import struct

## 'uint32 double'
data_string_in_orig    = 'b62e000052e366667a66408d'
data_string_in_swapped = '2eb60000e3526666667a8d40'
print data_string_in_orig

packed_data = binascii.unhexlify(data_string_in_swapped)
s = struct.Struct('<Id')
unpacked_data = s.unpack_from(packed_data, 0)  
print 'Unpacked Values:', unpacked_data

## Unpacked Values: (46638, 943.29999999943209)

exit(0)

【问题讨论】:

    标签: python string hex swap python-2.x


    【解决方案1】:

    array.arrays 有一个byteswap method

    import binascii
    import struct
    import array
    x = binascii.unhexlify('b62e000052e366667a66408d')
    y = array.array('h', x)  
    y.byteswap()
    s = struct.Struct('<Id')
    print(s.unpack_from(y))
    
    # (46638, 943.2999999994321)
    

    选择array.array('h', x) 中的h 是因为它告诉array.arrayx 中的数据视为2 字节短数组。重要的是每个项目都被视为 2 字节长。 H,表示 2 字节无符号短,同样有效。

    【讨论】:

    • array.byteswap。甜的。猜猜我会继续而不是发布我做饭的kludgy unpack big-endian / repack little-endian解决方案......
    • 继续发布吧!解决问题的方法不止一种可能很有用。
    • 谢谢,这对我来说既快速又完美。顺便说一下 100k 行在 5 秒内。
    • @WolfgangR。 - 如果此解决方案对您有用,您应该接受答案。
    【解决方案2】:

    这应该与 unutbu 的版本完全一样,但对于某些人来说可能更容易遵循......

    from binascii import unhexlify
    from struct import pack, unpack
    orig = unhexlify('b62e000052e366667a66408d')
    swapped = pack('<6h', *unpack('>6h', orig))
    print unpack('<Id', swapped)
    
    # (46638, 943.2999999994321)
    

    基本上,解压 6 shorts big-endian,重新打包为 6 shorts little-endian。

    同样,与 unutbu 的代码相同,您应该使用他的。

    edit 刚刚意识到我可以使用我最喜欢的 Python 习语来实现这一点……也不要这样做:

    orig = 'b62e000052e366667a66408d'
    swap =''.join(sum([(c,d,a,b) for a,b,c,d in zip(*[iter(orig)]*4)], ()))
    # '2eb60000e3526666667a8d40'
    

    【讨论】:

      【解决方案3】:

      从 'data_string_in_orig' 到 'data_string_in_swapped' 的交换也可以在不使用任何导入的情况下通过推导完成:

      >>> d = 'b62e000052e366667a66408d'
      >>> "".join([m[2:4]+m[0:2] for m in [d[i:i+4] for i in range(0,len(d),4)]])
      '2eb60000e3526666667a8d40'
      

      理解适用于交换表示 16 位字的十六进制字符串中的字节顺序。为不同的字长修改它是微不足道的。我们也可以做一个通用的十六进制数字顺序交换功能:

      def swap_order(d, wsz=4, gsz=2 ):
          return "".join(["".join([m[i:i+gsz] for i in range(wsz-gsz,-gsz,-gsz)]) for m in [d[i:i+wsz] for i in range(0,len(d),wsz)]])
      

      输入参数是:

      d : 输入的十六进制字符串

      wsz:以半字节为单位的字长(例如,对于 16 位字 wsz=4,对于 32 位字 wsz=8)

      gsz:保持在一起的半字节数(例如,重新排序字节 gsz=2,重新排序 16 位字 gsz = 4)

      【讨论】:

        【解决方案4】:
        import binascii, tkinter, array
        from tkinter import *
        
        infile_read = filedialog.askopenfilename()
        
        with open(infile, 'rb') as infile_:
            infile_read = infile_.read()
        
        x = (infile_read)
        y = array.array('l', x)
        y.byteswap()
        swapped = (binascii.hexlify(y))
        

        这是一个 32 位无符号短交换,我使用与“unutbu”答案非常相似的代码实现,只是更容易理解。从技术上讲,交换不需要 binascii。只需要 array.byteswap。

        【讨论】:

          猜你喜欢
          • 2023-03-14
          • 1970-01-01
          • 1970-01-01
          • 2012-09-25
          • 1970-01-01
          • 2020-11-11
          • 2019-07-27
          • 1970-01-01
          相关资源
          最近更新 更多