如何在Python中验证IP地址?

kru*_*pan 151 python validation networking ip-address

验证用户输入的IP有效的最佳方法是什么?它以字符串形式出现.

Dus*_*tin 176

不要解析它.请问.

import socket

try:
    socket.inet_aton(addr)
    # legal
except socket.error:
    # Not legal
Run Code Online (Sandbox Code Playgroud)

  • @bortzmeyer:如果你想支持ip6,socket.inet_pton(socket_family,address)就是你想要的.您仍需要指定系列.inet_aton特别不支持ip4以外的任何东西. (25认同)
  • 嗯,似乎接受像"4"和"192.168"这样的东西,然后用零默默地填充其余部分.技术上有效,我敢肯定,但不完全符合我的预期. (18认同)
  • 看起来Richo的回答解决了krupan和bortzmeyer的问题.使用socket.inet_pton与socket.AF_INET或socket.AF_INET6作为系列来验证ipv4和ipv6,而不接受不完整的地址. (9认同)
  • inet_aton()在接受"4","192.168"和"127.1"时不接受"无效"IP,它只是使用底层C行为 - 请参阅文档.127.1将127放在顶部八位位组中,并将1解析为24位数,并在剩余的三个八位位组中分割.这个想法是支持/ 16个增加IP的范围,所以你可以去172.16.1 ... 172.16.255然后172.16.256,而不是改变你的数学去172.16.1.0. (8认同)
  • 不,不适用于所有合法的IP地址:>>> socket.inet_aton("2001:660 :: 1")Traceback(最近一次调用最后一次):文件"<stdin>",第1行,在<module> socket中.error:传递给inet_aton的非法IP地址字符串 (6认同)

tzo*_*zot 66

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
Run Code Online (Sandbox Code Playgroud)

  • @quux:没有.这是一个长时间的讨论,人们不喜欢这样的事实:至少在Linux和Windows缩短的地址被认为是可以接受的.例如,`socket.inet_aton('127.1')`的计算结果为''\ x7f\x00\x00\x01'`(就像'127.0.0.1'那样).我在其他地方进行过这种令人厌倦和冗长的讨论,但是不记得在哪里记得. (10认同)
  • 在Windows上怎么样? (2认同)
  • @cowlinator `inet_pton` 仅存在于 Unix 中,而 `inet_aton` 存在于所有平台中,所以这是一个“以 Unix 为主”的答案。 (2认同)

Sam*_*ain 61

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'
Run Code Online (Sandbox Code Playgroud)

然而,就像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 "<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
Run Code Online (Sandbox Code Playgroud)

对于Python 2,如果安装python-ipaddress,则可以使用ipaddress获得相同的功能:

pip install ipaddress
Run Code Online (Sandbox Code Playgroud)

该模块与Python 2兼容,并提供了与Python 3.3之后的Python标准库中包含的ipaddress模块​​非常相似的API.更多细节在这里.在Python 2中,您需要将IP地址字符串显式转换为unicode : ipaddress.ip_address(u'127.0.0.1').


Yoh*_*ann 53

从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])
Run Code Online (Sandbox Code Playgroud)

对于其他版本: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
Run Code Online (Sandbox Code Playgroud)

sa:ipaddress 1.0.17,"IPv4/IPv6操作库","3.3+ ipaddress模块​​的端口",https: //pypi.python.org/pypi/ipaddress/1.0.17

  • 谢谢@Yohann。对于 Python 3.5,打印时需要括号。否则,代码将产生错误。由于空间有限,我将更新下面答案部分的代码。希望这对其他人也有帮助。 (2认同)

Mar*_*rot 43

def is_valid_ip(ip):
    """Validates IP addresses.
    """
    return is_valid_ipv4(ip) or is_valid_ipv6(ip)
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

IPv6版本使用" (?:(?<=::)|(?<!::):)",可以在(?(?<!::):)支持具有环视功能的条件的正则表达式引擎上替换为" ".(即PCRE,.NET)

编辑:

  • 删除了原生变体.
  • 扩展正则表达式以符合RFC.
  • 为IPv6地址添加了另一个正则表达式.

EDIT2:

我找到了一些链接,讨论如何使用正则表达式解析IPv6地址:

EDIT3:

最后设法编写了一个通过所有测试的模式,我也很高兴.


Grz*_*ywo 14

我希望它足够简单和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()))
Run Code Online (Sandbox Code Playgroud)

  • ;-) ^(\ d {1,3} \.){3}\d {1,3} $ (6认同)
  • @warfares 那是有原因的,它需要将组分开以检查值是否在 0 和 255 范围内,这就是返回的第二部分正在执行的操作,如果您想使用正则表达式,请使用 return bool(m ) 只要。 (2认同)

小智 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
    $"""
Run Code Online (Sandbox Code Playgroud)

我还整理了一个Python脚本来测试所有这些IPv6示例; 它位于Pastebin上,因为它太大而无法在此发布.

您可以使用"[result] = [example]"形式的测试结果和示例参数运行脚本,如下所示:

python script.py Fail=::1.2.3.4: pass=::127.0.0.1 false=::: True=::1
Run Code Online (Sandbox Code Playgroud)

或者您可以通过指定无参数来简单地运行所有测试,如下所示:

python script.py
Run Code Online (Sandbox Code Playgroud)

无论如何,我希望这有助于其他人!

  • 虽然我也很佩服你的努力,但我认为你的构造存在巨大的设计缺陷:它太大了!我永远不会相信这种规模的正则表达多年来没有成千上万的人使用过. (3认同)

chi*_*s42 6

我想这会做到......

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
Run Code Online (Sandbox Code Playgroud)

  • 代码错误,仅适用于IPv4地址. (6认同)
  • Python的int()强制在这里太宽松了; 例如,它剥离空格. (3认同)
  • 如果用户键入"abcd"而不是整数,您可能希望从int()中捕获ValueError异常. (2认同)
  • `192.168.178.0030`是有效的. (2认同)

小智 6

将 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"
Run Code Online (Sandbox Code Playgroud)