Преобразование шестнадцатеричной строки с прямым порядком байтов в IP-адрес в Python

Как лучше всего превратить строку в этой форме в IP-адрес: "0200A8C0". «Октеты», представленные в строке, расположены в обратном порядке, т. е. строка данного примера должна генерировать 192.168.0.2.


person Matt Joiner    schedule 04.02.2010    source источник


Ответы (4)


Управление сетевым адресом обеспечивается модулем сокета.

socket.inet_ntoa(packed_ip)

Преобразуйте 32-битный упакованный IPv4-адрес (строка длиной четыре символа) в его стандартное представление строки с четырьмя точками (например, «123.45.67.89»). Это полезно при взаимодействии с программой, которая использует стандартную библиотеку C и нуждается в объектах типа struct in_addr, который является типом C для 32-битных упакованных двоичных данных, которые эта функция принимает в качестве аргумента.

Вы можете преобразовать свою шестнадцатеричную строку в packed ip, используя struct.pack() и обратный порядок байтов , беззнаковый длинный формат.

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'
person gimel    schedule 04.02.2010
comment
Вы хотите ‹I, а не L в качестве первого аргумента pack, хотя ‹L тоже будет работать. В противном случае вы оставляете себя открытым для любой платформы endianess. - person Omnifarious; 04.02.2010
comment
@Omnifarious, как именно это влияет на это здесь? - person Matt Joiner; 04.02.2010
comment
@ Мэтт Джойнер, на самом деле это не так, по крайней мере, если вы сделаете ‹L. В противном случае это зависит от платформы, насколько велики L или I. У меня есть тенденция использовать концептуально наименьший шрифт, который работает. - person Omnifarious; 04.02.2010
comment
Отредактировано на ‹L. Спасибо, @Всемогущий. - person gimel; 04.02.2010
comment
192.168.10.5 шестнадцатеричное число равно c0a80a05. Когда я использую этот фрагмент для преобразования из HEX в IP, я получаю 5.10.168.192. Что правильно, но наоборот. Чтобы заставить его работать, я должен изменить <L на >L, что не имеет никакого смысла, если я получаю ввод от пользователя, и я не знаю, какой HEX является вводом! У вас есть идеи, как заставить его работать для любого шестнадцатеричного значения? Спасибо - person Tes3awy; 14.04.2021

>>> 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
person Community    schedule 04.02.2010
comment
@ Роджер, как это работает zip(*[iter(s)]*2)? Я очень заинтересован в этом. - person Matt Joiner; 04.02.2010
comment
Это настоящий хак! iter(s) возвращает итератор по строке. Умножение списка этого итератора на 2 создаст две ссылки на один и тот же итератор. zip() возвращает список кортежей, содержащих элемент из каждого из своих аргументов. Поскольку оба аргумента являются одним и тем же итератором, он будет брать из него дважды для каждого кортежа, возвращая кортеж из каждых 2-х соседних символов. Мне бы никогда не пришло в голову попробовать что-то подобное. :D - person Max Shawabkeh; 04.02.2010
comment
@Matt: Это основа большинства рецептов группировки, которые я видел, и Макс хорошо это объяснил. Будет обновлено, чтобы включить две короткие функции в этом духе. - person ; 04.02.2010
comment
@ Роджер, большое спасибо, я надеялся, что появится решение, подобное вашему. - person Matt Joiner; 04.02.2010
comment
Я создал новый вопрос, который напрямую спрашивает, что вы решили здесь: stackoverflow.com/questions/2202461/ - person Matt Joiner; 04.02.2010
comment
+1 Этот трюк с застежкой-молнией невероятно полезен для гольфа кода. Потрясающий. - person Exelian; 01.09.2011

Вы можете сделать что-то вроде этого:

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

Разбиение октетов, вероятно, можно было бы сделать более элегантно, но я не могу придумать более простой способ.

EDIT: Или в одной строке:

>>> 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
person Max Shawabkeh    schedule 04.02.2010
comment
да группировка в особенности добирается до меня. я не могу найти хороший способ разбить октеты и перебрать эти в обратном порядке, я надеюсь, что кто-то знает способ - person Matt Joiner; 04.02.2010
comment
@ Макс, ответ Роджера содержит очень интригующий способ сделать это. - person Matt Joiner; 04.02.2010

Моя попытка:

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