【问题标题】:Convert "little endian" hex string to IP address in Python在 Python 中将“little endian”十六进制字符串转换为 IP 地址
【发布时间】:2023-03-20 21:25:01
【问题描述】:

将这种形式的字符串转换为 IP 地址的最佳方法是:"0200A8C0"。字符串中的“八位字节”顺序相反,即给定的示例字符串应该生成192.168.0.2

【问题讨论】:

    标签: python sockets ip-address endianness


    【解决方案1】:

    网络地址操作由套接字模块提供。

    socket.inet_ntoa(packed_ip)

    将 32 位压缩 IPv4 地址(长度为四个字符的字符串)转换为其标准点分四进制字符串表示形式(例如,“123.45.67.89”)。这在与使用标准 C 库并需要 struct in_addr 类型的对象的程序进行对话时很有用,这是该函数作为参数的 32 位打包二进制数据的 C 类型。

    您可以使用struct.pack() 将您的十六进制字符串转换为packed ip 和小端、无符号长格式。

    s = "0200A8C0"
    
    import socket
    import struct
    addr_long = int(s, 16)
    print(hex(addr_long))  # '0x200a8c0'
    print(struct.pack("<L", addr_long))  # '\xc0\xa8\x00\x02'
    print(socket.inet_ntoa(struct.pack("<L", addr_long)))  # '192.168.0.2'
    

    【讨论】:

    • 你想要“pack 的第一个参数,尽管“
    • @Omnifarious,它的“long/int”究竟是如何影响它的?
    • @Matt Joiner,它不是真的,至少如果你做“
    • 编辑为“
    • 192.168.10.5 十六进制为 c0a80a05。当我使用这个 sn-p 从 HEX 转换为 IP 时,我得到5.10.168.192。这是正确的,但相反。为了使它工作,我必须将&lt;L 更改为&gt;L,如果我从用户那里获取输入并且我不知道输入是什么十六进制,这没有任何意义!你知道如何让它适用于任何 HEX 值吗?谢谢
    【解决方案2】:
    >>> s = "0200A8C0"
    >>> bytes = ["".join(x) for x in zip(*[iter(s)]*2)]
    >>> bytes
    ['02', '00', 'A8', 'C0']
    >>> bytes = [int(x, 16) for x in bytes]
    >>> bytes
    [2, 0, 168, 192]
    >>> print ".".join(str(x) for x in reversed(bytes))
    192.168.0.2
    

    简洁明了;将其封装在一个带有错误检查功能的函数中以满足您的需求。


    方便的分组功能:

    def group(iterable, n=2, missing=None, longest=True):
      """Group from a single iterable into groups of n.
    
      Derived from http://bugs.python.org/issue1643
      """
      if n < 1:
        raise ValueError("invalid n")
      args = (iter(iterable),) * n
      if longest:
        return itertools.izip_longest(*args, fillvalue=missing)
      else:
        return itertools.izip(*args)
    
    def group_some(iterable, n=2):
      """Group from a single iterable into groups of at most n."""
      if n < 1:
        raise ValueError("invalid n")
      iterable = iter(iterable)
      while True:
        L = list(itertools.islice(iterable, n))
        if L:
          yield L
        else:
          break
    

    【讨论】:

    • @Roger,zip(*[iter(s)]*2) 是如何工作的?我对此很感兴趣。
    • 这真是太棒了! iter(s) 在字符串上返回一个迭代器。将此迭代器的列表乘以 2 将创建两个对同一迭代器的引用。 zip() 返回一个元组列表,其中包含每个参数中的一个元素。由于两个参数都是相同的迭代器,因此每个元组将从它获取两次,返回每 2 个相邻字符的元组。我从来没有想过尝试这样的事情。 :D
    • @Matt:这是我见过的大多数“分组”食谱的核心,Max 解释得很好。将更新以包含这方面的两个简短功能。
    • @Roger,非常感谢,我希望能找到像你这样的解决方案。
    • 我新建了一个问题,直接问你这里解决了什么问题:stackoverflow.com/questions/2202461/…
    【解决方案3】:

    你可以这样做:

    >>> s = '0200A8C0'
    >>> octets = [s[i:i+2] for i in range(0, len(s), 2)]
    >>> ip = [int(i, 16) for i in reversed(octets)]
    >>> ip_formatted = '.'.join(str(i) for i in ip)
    >>> print ip_formatted
    192.168.0.2
    

    八位字节拆分可能会更优雅,但我想不出更简单的方法。

    编辑:或一行:

    >>> s = '0200A8C0'
    >>> print '.'.join(str(int(i, 16)) for i in reversed([s[i:i+2] for i in range(0, len(s), 2)]))
    192.168.0.2
    

    【讨论】:

    • 是的,特别是分组对我来说很重要。我找不到一个很好的方法来“分块”八位字节,并以相反的顺序迭代 那些,我希望有人知道方法
    • @Max,Roger 的回答包含一个非常有趣的方法。
    【解决方案4】:

    我的尝试:

    a = '0200A8C0'
    indices = range(0, 8, 2)
    data = [str(int(a[x:x+2], 16)) for x in indices]
    '.'.join(reversed(data))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-05
      • 2013-09-01
      • 2020-06-05
      • 1970-01-01
      • 1970-01-01
      • 2012-09-13
      • 1970-01-01
      • 2014-06-27
      相关资源
      最近更新 更多