Как лучше всего проверить действительность введенного пользователем IP-адреса? Он поступает в виде строки.
import ipaddress; ipaddress.ipaddress(your_input_text) и ловите ValueError. Это в stdlib.






Я думаю, это сработает ...
def validIP(address):
parts = address.split(".")
if len(parts) != 4:
return False
for item in parts:
if not 0 <= int(item) <= 255:
return False
return True
Вы можете захотеть перехватить исключение ValueError из int () в случае, если пользователь вводит «a.b.c.d», а не целые числа.
Неверный код, работает только с IPv4-адресами.
Принуждение Python int () здесь слишком слабое; например, он удаляет пробелы.
192.168.178.0030 будет действительным.
не работает для ipv6.
def is_valid_ip(ip):
"""Validates IP addresses.
"""
return is_valid_ipv4(ip) or is_valid_ipv6(ip)
IPv4:
def is_valid_ipv4(ip):
"""Validates IPv4 addresses.
"""
pattern = re.compile(r"""
^
(?:
# Dotted variants:
(?:
# Decimal 1-255 (no leading 0's)
[3-9]\d?|2(?:5[0-5]|[0-4]?\d)?|1\d{0,2}
|
0x0*[0-9a-f]{1,2} # Hexadecimal 0x0 - 0xFF (possible leading 0's)
|
0+[1-3]?[0-7]{0,2} # Octal 0 - 0377 (possible leading 0's)
)
(?: # Repeat 0-3 times, separated by a dot
\.
(?:
[3-9]\d?|2(?:5[0-5]|[0-4]?\d)?|1\d{0,2}
|
0x0*[0-9a-f]{1,2}
|
0+[1-3]?[0-7]{0,2}
)
){0,3}
|
0x0*[0-9a-f]{1,8} # Hexadecimal notation, 0x0 - 0xffffffff
|
0+[0-3]?[0-7]{0,10} # Octal notation, 0 - 037777777777
|
# Decimal notation, 1-4294967295:
429496729[0-5]|42949672[0-8]\d|4294967[01]\d\d|429496[0-6]\d{3}|
42949[0-5]\d{4}|4294[0-8]\d{5}|429[0-3]\d{6}|42[0-8]\d{7}|
4[01]\d{8}|[1-3]\d{0,9}|[4-9]\d{0,8}
)
$
""", re.VERBOSE | re.IGNORECASE)
return pattern.match(ip) is not None
IPv6:
def is_valid_ipv6(ip):
"""Validates IPv6 addresses.
"""
pattern = re.compile(r"""
^
\s* # Leading whitespace
(?!.*::.*::) # Only a single whildcard allowed
(?:(?!:)|:(?=:)) # Colon iff it would be part of a wildcard
(?: # Repeat 6 times:
[0-9a-f]{0,4} # A group of at most four hexadecimal digits
(?:(?<=::)|(?<!::):) # Colon unless preceeded by wildcard
){6} #
(?: # Either
[0-9a-f]{0,4} # Another group
(?:(?<=::)|(?<!::):) # Colon unless preceeded by wildcard
[0-9a-f]{0,4} # Last group
(?: (?<=::) # Colon iff preceeded by exacly one colon
| (?<!:) #
| (?<=:) (?<!::) : #
) # OR
| # A v4 address with NO leading zeros
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]?\d)
(?: \.
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]?\d)
){3}
)
\s* # Trailing whitespace
$
""", re.VERBOSE | re.IGNORECASE | re.DOTALL)
return pattern.match(ip) is not None
Версия IPv6 использует «(?:(?<=::)|(?<!::):)», который можно заменить на «(?(?<!::):)» в механизмах регулярных выражений, которые поддерживают условные выражения с просмотром. (например, PCRE, .NET)
Редактировать:
Edit2:
Я нашел несколько ссылок, в которых обсуждается, как анализировать IPv6-адреса с помощью регулярного выражения:
Edit3:
Наконец-то удалось написать шаблон, который проходит все тесты, и этим я тоже доволен.
Нет, работает только с IPv4-адресами.
test-ipv6-regex.pl - золото +1
Кажется, не работает с адресами IPv6, в которых используются квадратные скобки (например, для указания номера порта): [2001:4860:4860::8888]:80
Я думаю, что этот способ очень непифонический и слишком сложный. Достаточно простого вызова с ipaddress.ip_address.
Не разбирайте это. Просто спроси.
import socket
try:
socket.inet_aton(addr)
# legal
except socket.error:
# Not legal
Хм, похоже, принимает такие вещи, как «4» и «192.168», а остальные молча дополняет нулями. Я уверен, что технически верно, но не совсем то, что я ожидал.
Это действительные представления IP-адресов. 127.1 - это localhost, 1172703390 - мой веб-сервер. Если вы хотите убедиться, что он находится в четырехугольнике с точками, вы также можете проверить, что len (addr.split ('.')) == 4
@krupan: вы можете объединить вышеуказанное с тестом на "len (addr.split (". ")) == 4", если вы хотите отклонить более короткие адреса.
Нет, не работает со всеми допустимыми IP-адресами: >>> socket.inet_aton ("2001: 660 :: 1") Traceback (последний вызов последним): файл "<stdin>", строка 1, в сокете <module> .error: неверная строка IP-адреса передана inet_aton
@bortzmeyer: socket.inet_pton (socket_family, address) - это то, что вам нужно, если вы хотите поддерживать ip6. Еще нужно указать семью. inet_aton конкретно ничего кроме ip4 не поддерживает.
Похоже, что ответ Рихо решает вопросы Крупана и Борцмейера. Используйте socket.inet_pton с socket.AF_INET или socket.AF_INET6 в качестве семейства для проверки ipv4 и ipv6 без принятия неполных адресов.
Теперь есть официальный способ манипулировать адресами IPv4 и Ipv6 в python PEP 3144. См. Мой ответ выше.
inet_aton () не принимает «недопустимые» IP-адреса, когда принимает «4», «192.168» и «127.1», он просто использует базовое поведение C - см. документацию. 127.1 помещает 127 в верхний октет и анализирует 1 как 24-битное число, которое разделяет на оставшиеся три октета. Идея состоит в том, чтобы поддерживать диапазоны / 16, которые увеличивают IP-адреса, поэтому вы можете перейти на 172.16.1 ... 172.16.255, а затем на 172.16.256, вместо того, чтобы изменять свои математические вычисления, чтобы перейти к 172.16.1.0.
@richo - inet_pton доступен только в некоторых вариантах Unix, а в Windows он вообще недоступен.
Это не позволяет проверять IP на соответствие RFC790.
Стоит отметить, что существуют проблемы безопасности с модулем сокета, который использует функцию glibc inet_aton (), которая «принимает конечный мусор по историческим причинам», как сообщается здесь: bugzilla.redhat.com/show_bug.cgi?id=1347549. Red Had Product Security оценил эту проблему как имеющую среднее влияние на безопасность, и поэтому вряд ли она будет решена в ближайшее время. Учитывая это, я бы сказал, что хорошее регулярное выражение - лучший инструмент для этого.
Почему 4 или 192.168 - действительный IP-адрес?
@MartinThoma из справочной страницы инет: «Значение a интерпретируется как 32-битное значение, которое сохраняется непосредственно в двоичный адрес без какой-либо перестановки байтов»
Модуль IPy (модуль, предназначенный для работы с IP-адресами) вызовет исключение ValueError для недопустимых адресов.
>>> from IPy import IP
>>> IP('127.0.0.1')
IP('127.0.0.1')
>>> IP('277.0.0.1')
Traceback (most recent call last):
...
ValueError: '277.0.0.1': single byte must be 0 <= byte < 256
>>> IP('foobar')
Traceback (most recent call last):
...
ValueError: invalid literal for long() with base 10: 'foobar'
Однако, как и ответ Дастина, он будет принимать такие вещи, как «4» и «192.168», поскольку, как уже упоминалось, это действительные представления IP-адресов.
Если вы используете Python 3.3 или новее, теперь он включает модуль ipaddress:
>>> import ipaddress
>>> ipaddress.ip_address('127.0.0.1')
IPv4Address('127.0.0.1')
>>> ipaddress.ip_address('277.0.0.1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.3/ipaddress.py", line 54, in ip_address
address)
ValueError: '277.0.0.1' does not appear to be an IPv4 or IPv6 address
>>> ipaddress.ip_address('foobar')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.3/ipaddress.py", line 54, in ip_address
address)
ValueError: 'foobar' does not appear to be an IPv4 or IPv6 address
Для Python 2 вы можете получить ту же функциональность с помощью ipaddress, если установите python-ipaddress:
pip install ipaddress
Этот модуль совместим с Python 2 и предоставляет API, очень похожий на API модуля ipaddress, включенного в стандартную библиотеку Python начиная с Python 3.3. Подробнее здесь. В Python 2 вам нужно будет явно преобразовать строку IP-адреса в unicode: ipaddress.ip_address(u'127.0.0.1').
Замечательная идея. Единственное решение, представленное до сих пор, которое работает со всеми IP-адресами. >>> из IPy импортировать IP >>> IP ("2001: 660 :: 1") IP ('2001: 660 :: 1')
Для python 2, pip install ipaddress, вы получите почти тот же API :)
Что касается import ipaddress, когда я передавал адрес IPv4, я получал результат как IPv4Address('127.0.0.1'). Но когда я попытался преобразовать его в string, чтобы проверить, содержит ли он IPv4 или IPv6, я только что получил IP. Как я могу узнать в коде, это IPv4 или IPv6? if "IPv4" in str(type(val)): - хорошая идея?
Проделал точно такие же действия и получил ipaddress.AddressValueError: '127.0.0.1' does not appear to be a n IPv4 or IPv6 address. Did you pass in a bytes (str in Python 2) instead of a unicode object?. Справка, представленная в сообщении об ошибке, помогла мне решить проблему. Вам нужен u'...' в Python 2.
Решение очень простое: try: return bool(ipaddress.ip_address(ip)) except ValueError: return False
import socket
def is_valid_ipv4_address(address):
try:
socket.inet_pton(socket.AF_INET, address)
except AttributeError: # no inet_pton here, sorry
try:
socket.inet_aton(address)
except socket.error:
return False
return address.count('.') == 3
except socket.error: # not a valid address
return False
return True
def is_valid_ipv6_address(address):
try:
socket.inet_pton(socket.AF_INET6, address)
except socket.error: # not a valid address
return False
return True
Почему строчка: «return address.count ('.') == 3» ?? Это осталось от вашей отладки?
@quux: нет. Это долгое обсуждение, и людям не нравится тот факт, что, по крайней мере, в Linux и Windows сокращенные адреса считаются приемлемыми. Например, socket.inet_aton('127.1') оценивается как '\x7f\x00\x00\x01' (т.е. точно так же, как 127.0.0.1). У меня было это утомительное и долгое обсуждение в другом месте на SO, но не могу вспомнить, где.
Как насчет окон?
Обратите внимание, что это ответ только для unix
@cowlinator inet_pton существует только в Unix, а inet_aton существует на всех платформах, так что это ответ «в основном unix».
Начиная с Python 3.4, лучший способ проверить правильность адреса IPv6 или IPv4 - использовать модуль стандартной библиотеки Python ipaddress - библиотеку управления IPv4 / IPv6 s.a. https://docs.python.org/3/library/ipaddress.html для полной документации.
Пример :
#!/usr/bin/env python
import ipaddress
import sys
try:
ip = ipaddress.ip_address(sys.argv[1])
print('%s is a correct IP%s address.' % (ip, ip.version))
except ValueError:
print('address/netmask is invalid: %s' % sys.argv[1])
except:
print('Usage : %s ip' % sys.argv[0])
Для других версий: Github, phihag / Philipp Hagemeister, «ipaddress Python 3.3 для более старых версий Python», https://github.com/phihag/ipaddress
Бэкпорт от phihag доступен, например. в Anaconda Python 2.7 и включен в установщик. s.a. https://docs.continuum.io/anaconda/pkg-docs
Чтобы установить с помощью pip:
pip install ipaddress
s.a .: ipaddress 1.0.17, «Библиотека управления IPv4 / IPv6», «Порт модуля ipaddress 3.3+», https://pypi.python.org/pypi/ipaddress/1.0.17
Я получаю эту ошибку C:\Python\Codes>check_ip.py File "C:\Python\Codes\check_ip.py", line 8 print '%s is a correct IP%s address.' % (ip, ip.version) ^ SyntaxError: invalid syntax C:\Python\Codes>
Спасибо @Yohann. Для Python 3.5 круглые скобки требуются при печати. В противном случае код выдаст ошибку. Поскольку это место ограничено, я обновлю код в разделе ответов ниже. Надеюсь, это поможет и другим.
Это вернет неверный ответ для test.example.com. Получил IPv6Address(u'7465:7374:2e65:7861:6d70:6c65:2e63:6f6d')
Извините, новичок здесь. Какую роль в этом примере играет sys.argv[0]/[1]? Это просто тестовые параметры (примеры IP-адресов), которые вы передаете при запуске скрипта, или они требуются при реализации? Из чтения здесь кажется, что это просто тестовые параметры.
Я должен отдать должное Маркусу Жардеро за его пост - большая часть моего поста вдохновлена его.
Я обнаружил, что ответ Маркуса по-прежнему не соответствует некоторым примерам IPv6 в сценарии Perl, на который ссылается его ответ.
Вот мое регулярное выражение, которое передает все примеры из этого сценария Perl:
r"""^
\s* # Leading whitespace
# Zero-width lookaheads to reject too many quartets
(?:
# 6 quartets, ending IPv4 address; no wildcards
(?:[0-9a-f]{1,4}(?::(?!:))){6}
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)
(?:\.(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}
|
# 0-5 quartets, wildcard, ending IPv4 address
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,4}[0-9a-f]{1,4})?
(?:::(?!:))
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)
(?:\.(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}
|
# 0-4 quartets, wildcard, 0-1 quartets, ending IPv4 address
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,3}[0-9a-f]{1,4})?
(?:::(?!:))
(?:[0-9a-f]{1,4}(?::(?!:)))?
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)
(?:\.(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}
|
# 0-3 quartets, wildcard, 0-2 quartets, ending IPv4 address
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,2}[0-9a-f]{1,4})?
(?:::(?!:))
(?:[0-9a-f]{1,4}(?::(?!:))){0,2}
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)
(?:\.(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}
|
# 0-2 quartets, wildcard, 0-3 quartets, ending IPv4 address
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,1}[0-9a-f]{1,4})?
(?:::(?!:))
(?:[0-9a-f]{1,4}(?::(?!:))){0,3}
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)
(?:\.(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}
|
# 0-1 quartets, wildcard, 0-4 quartets, ending IPv4 address
(?:[0-9a-f]{1,4}){0,1}
(?:::(?!:))
(?:[0-9a-f]{1,4}(?::(?!:))){0,4}
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)
(?:\.(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}
|
# wildcard, 0-5 quartets, ending IPv4 address
(?:::(?!:))
(?:[0-9a-f]{1,4}(?::(?!:))){0,5}
(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)
(?:\.(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}
|
# 8 quartets; no wildcards
(?:[0-9a-f]{1,4}(?::(?!:))){7}[0-9a-f]{1,4}
|
# 0-7 quartets, wildcard
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,6}[0-9a-f]{1,4})?
(?:::(?!:))
|
# 0-6 quartets, wildcard, 0-1 quartets
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,5}[0-9a-f]{1,4})?
(?:::(?!:))
(?:[0-9a-f]{1,4})?
|
# 0-5 quartets, wildcard, 0-2 quartets
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,4}[0-9a-f]{1,4})?
(?:::(?!:))
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,1}[0-9a-f]{1,4})?
|
# 0-4 quartets, wildcard, 0-3 quartets
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,3}[0-9a-f]{1,4})?
(?:::(?!:))
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,2}[0-9a-f]{1,4})?
|
# 0-3 quartets, wildcard, 0-4 quartets
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,2}[0-9a-f]{1,4})?
(?:::(?!:))
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,3}[0-9a-f]{1,4})?
|
# 0-2 quartets, wildcard, 0-5 quartets
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,1}[0-9a-f]{1,4})?
(?:::(?!:))
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,4}[0-9a-f]{1,4})?
|
# 0-1 quartets, wildcard, 0-6 quartets
(?:[0-9a-f]{1,4})?
(?:::(?!:))
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,5}[0-9a-f]{1,4})?
|
# wildcard, 0-7 quartets
(?:::(?!:))
(?:(?:[0-9a-f]{1,4}(?::(?!:))){0,6}[0-9a-f]{1,4})?
)
(?:/(?:1(?:2[0-7]|[01]\d)|\d\d?))? # With an optional CIDR routing prefix (0-128)
\s* # Trailing whitespace
$"""
Я также собрал сценарий Python для тестирования всех этих примеров IPv6; это здесь, на Pastebin, потому что он был слишком большим для публикации здесь.
Вы можете запустить скрипт с результатом теста и примерами аргументов в форме «[результат] = [пример]», например:
python script.py Fail=::1.2.3.4: pass=::127.0.0.1 false=::: True=::1
или вы можете просто запустить все тесты, не указав аргументов, например:
python script.py
В любом случае, я надеюсь, что это поможет кому-то другому!
Хотя я тоже восхищаюсь вашими усилиями, я думаю, что в вашей конструкции есть огромный недостаток: она слишком велика! Я бы никогда не поверил регулярному выражению такого размера, которое не использовалось тысячами людей в течение многих лет.
@ erikb85: Взгляните на сценарий, который я опубликовал в Pastebin. Он содержит 1154 теста различных форматов IPv6 и проходит каждый из из них. Если вы считаете, что необходимы дополнительные тесты, не стесняйтесь изменять мой сценарий, добавлять тесты и публиковать результаты.
Мне нужно было только разобрать IP-адреса v4. Мое решение, основанное на стратегии Chills, следующее:
def getIP():
valid = False
while not valid :
octets = raw_input( "Remote Machine IP Address:" ).strip().split(".")
try: valid=len( filter( lambda(item):0<=int(item)<256, octets) ) == 4
except: valid = False
return ".".join( octets )
Надеюсь, это достаточно просто и питонично:
def is_valid_ip(ip):
m = re.match(r"^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$", ip)
return bool(m) and all(map(lambda n: 0 <= int(n) <= 255, m.groups()))
вы повторяете один и тот же узор 3 раза ...
;-) ^ (\ d {1,3} \.) {3} \ d {1,3} $
@warfaresthat по какой-то причине, ему нужны группы, разделенные, чтобы проверить, находятся ли значения в диапазоне от 0 до 255, это то, что делает вторая часть возврата, если вы хотите использовать свое регулярное выражение, используйте return bool (m ) Только.
Я придумал эту простую версию для новичков
def ip_checkv4(ip):
parts=ip.split(".")
if len(parts)<4 or len(parts)>4:
return "invalid IP length should be 4 not greater or less than 4"
else:
while len(parts)== 4:
a=int(parts[0])
b=int(parts[1])
c=int(parts[2])
d=int(parts[3])
if a<= 0 or a == 127 :
return "invalid IP address"
elif d == 0:
return "host id should not be 0 or less than zero "
elif a>=255:
return "should not be 255 or greater than 255 or less than 0 A"
elif b>=255 or b<0:
return "should not be 255 or greater than 255 or less than 0 B"
elif c>=255 or c<0:
return "should not be 255 or greater than 255 or less than 0 C"
elif d>=255 or c<0:
return "should not be 255 or greater than 255 or less than 0 D"
else:
return "Valid IP address ", ip
p=raw_input("Enter IP address")
print ip_checkv4(p)
Считайте IPv4-адрес «ip».
if re.match(r'^((\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])\.){3}(\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])$', ip):
print "Valid IP"
else:
print "Invalid IP"
Я просто хочу отметить, что если широковещательный адрес не считается действительным адресом, то каждое из предложенных до сих пор решений терпит неудачу. Вы должны проверить маску подсети, чтобы узнать, является ли это широковещательным адресом.