验证用户输入的IP有效的最佳方法是什么?它以字符串形式出现.
不要解析它.请问.
import socket try: socket.inet_aton(addr) # legal except socket.error: # Not legal
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
该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'
然而,就像Dustin的回答一样,它会接受"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 "", line 1, in 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 " ", line 1, in 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,如果安装python-ipaddress,则可以使用ipaddress获得相同的功能:
pip install ipaddress
该模块与Python 2兼容,并提供了与Python 3.3之后的Python标准库中包含的ipaddress模块非常相似的API.更多细节在这里.在Python 2中,您需要将IP地址字符串显式转换为unicode : ipaddress.ip_address(u'127.0.0.1')
.
从Python 3.4开始,检查IPv6或IPv4地址是否正确的最佳方法是使用Python标准库模块ipaddress
- IPv4/IPv6操作库sa 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,"Python 3.3的旧版Python版ipaddress",https://github.com/phihag/ipaddress
来自phihag的后端可以在例如Anaconda Python 2.7中获得,并且包含在安装程序中.sa https://docs.continuum.io/anaconda/pkg-docs
要用pip安装:
pip install ipaddress
sa:ipaddress 1.0.17,"IPv4/IPv6操作库","3.3+ ipaddress模块的端口",https: //pypi.python.org/pypi/ipaddress/1.0.17
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 (?:(?<=::)|(?IPv6版本使用"
(?:(?<=::)|(?",可以在
(?(?支持具有环视功能的条件的正则表达式引擎上替换为" ".(即PCRE,.NET)
编辑:
删除了原生变体.
扩展正则表达式以符合RFC.
为IPv6地址添加了另一个正则表达式.
EDIT2:
我找到了一些链接,讨论如何使用正则表达式解析IPv6地址:
IPv6地址的正则表达式 - InterMapper论坛
使用IPv6正则表达式 - Patrick的游乐场博客
test-ipv6-regex.pl - 包含大量测试用例的Perl脚本.看来我的正则表达式在一些测试中失败了.
EDIT3:
最后设法编写了一个通过所有测试的模式,我也很高兴.
6> Grzegorz Luc..:我希望它足够简单和pythonic:
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()))
;-) ^(\ d {1,3} \.){3}\d {1,3} $
7> 小智..:我必须给马库斯·贾德罗特(Markus Jarderot)的帖子提供很多信誉 - 我的大多数帖子都是从他的文章中获得灵感.
我发现Markus的答案仍然没有通过他的回答引用的Perl脚本中的一些IPv6示例.
这是我的正则表达式,它传递了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上,因为它太大而无法在此发布.
您可以使用"[result] = [example]"形式的测试结果和示例参数运行脚本,如下所示:
python script.py Fail=::1.2.3.4: pass=::127.0.0.1 false=::: True=::1或者您可以通过指定无参数来简单地运行所有测试,如下所示:
python script.py无论如何,我希望这有助于其他人!
虽然我也很佩服你的努力,但我认为你的构造存在巨大的设计缺陷:它太大了!我永远不会相信这种规模的正则表达多年来没有成千上万的人使用过.
8> chills42..:我想这会做到......
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
代码错误,仅适用于IPv4地址.
Python的int()强制在这里太宽松了; 例如,它剥离空格.
如果用户键入"abcd"而不是整数,您可能希望从int()中捕获ValueError异常.
`192.168.178.0030`是有效的.