【问题标题】:check if a string matches an IP address pattern in python?检查字符串是否与python中的IP地址模式匹配?
【发布时间】:2011-03-28 15:03:26
【问题描述】:

检查字符串是否匹配特定模式的最快方法是什么?正则表达式是最好的方法吗?

例如,我有一堆字符串,想检查每个字符串是否是有效的 IP 地址(在这种情况下有效意味着格式正确),是使用正则表达式执行此操作的最快方法吗?或者是否有更快的字符串格式或其他东西。

到目前为止,我一直在做这样的事情:

for st in strs:
    if re.match('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', st) != None:
       print 'IP!'

【问题讨论】:

    标签: python


    【解决方案1】:

    更新:下面的原始答案适用于 2011 年,但自 2012 年以来,使用 Python 的 ipaddress stdlib module 可能会更好 - 除了检查 IPv4 和 IPv6 的 IP 有效性之外,它还可以做很多事情其他事情也是如此。</update>

    您似乎正在尝试validate IP addresses。正则表达式可能不是最好的工具。

    如果您想接受所有有效的 IP 地址(包括一些您可能甚至不知道有效的地址),那么您可以使用 IPy (Source)

    from IPy import IP
    IP('127.0.0.1')
    

    如果IP地址无效会抛出异常。

    或者你可以使用socket(Source):

    import socket
    try:
        socket.inet_aton(addr)
        # legal
    except socket.error:
        # Not legal
    

    如果您真的只想匹配带有 4 个小数部分的 IPv4,那么您可以按点拆分并测试每个部分是否为 0 到 255 之间的整数。

    def validate_ip(s):
        a = s.split('.')
        if len(a) != 4:
            return False
        for x in a:
            if not x.isdigit():
                return False
            i = int(x)
            if i < 0 or i > 255:
                return False
        return True
    

    请注意,您的正则表达式不会执行此额外检查。它将接受999.999.999.999 作为有效地址。

    【讨论】:

    • 为 IPy 接受这个。我最终使用了 IPy,部分原因是 @Alex 的 IPv6 点。
    • IP 地址是否可以接受前导 0?例如,0.0.0.1 是有效 IP 吗?
    • 值得注意的是,socket 模块存在安全问题,该模块使用 glibc inet_aton() 函数,“由于历史原因接受尾随垃圾”,如下所述:bugzilla.redhat.com/show_bug.cgi?id=1347549。 Red Had Product Security 将此问题评为具有中等安全影响,因此不太可能很快得到解决。鉴于此,我认为一个好的正则表达式最好的工具。
    • (我编辑了指向 Python 的 ipaddress 的答案 - 我对文本中的干预表示歉意,但似乎很多互联网都指向这个答案 - 我认为这里的链接会帮助更多的人,而不是迟到 7 年的晦涩答案,甚至第二个答案也可能被忽略)
    • 您可能甚至不知道的一些有效地址是什么意思?
    【解决方案2】:

    如果你使用Python3,你可以使用ipaddress模块http://docs.python.org/py3k/library/ipaddress.html。示例:

    >>> import ipaddress
    
    >>> ipv6 = "2001:0db8:0a0b:12f0:0000:0000:0000:0001"
    >>> ipv4 = "192.168.2.10"
    >>> ipv4invalid = "266.255.9.10"
    >>> str = "Tay Tay"
    
    >>> ipaddress.ip_address(ipv6)
    IPv6Address('2001:db8:a0b:12f0::1')
    
    >>> ipaddress.ip_address(ipv4)
    IPv4Address('192.168.2.10')
    
    >>> ipaddress.ip_address(ipv4invalid)
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
      File "/usr/lib/python3.4/ipaddress.py", line 54, in ip_address
        address)
    ValueError: '266.255.9.10' does not appear to be an IPv4 or IPv6 address
    
    >>> ipaddress.ip_address(str)
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
      File "/usr/lib/python3.4/ipaddress.py", line 54, in ip_address
        address)
    ValueError: 'Tay Tay' does not appear to be an IPv4 or IPv6 address
    

    【讨论】:

      【解决方案3】:

      我通常是极少数坚定捍卫正则表达式的 Python 专家之一(他们在 Python 社区中的名声很差),但这不是其中之一——接受(比如说)'333.444.555.666'因为“IP 地址”真的很糟糕,如果您在匹配 RE 后需要进行更多检查,那么无论如何都会丢失使用 RE 的大部分意义。所以,我衷心支持@Mark 的建议:IPy 的通用性和优雅性(如果您愿意,包括对 IPv6 的支持!),字符串操作和 int 检查您是否只需要 IPv4(但是,请三思而后行,然后再想一想更多 -- IPv6 的时代已经到来!-):

      def isgoodipv4(s):
          pieces = s.split('.')
          if len(pieces) != 4: return False
          try: return all(0<=int(p)<256 for p in pieces)
          except ValueError: return False
      

      我宁愿这样做,也不愿使用复杂的 RE 来匹配 0 到 255 之间的数字!-)

      【讨论】:

      • +1 用于使用a&lt;=x&lt;b 和其他使其比我的尝试更干净的东西。
      • 虽然我完全同意您回答的主要观点,但此处发布的代码仅检查长度 4,而像 127.1 这样的地址是有效的(socket.inet_aton 同意,并且可以 ping 通这些地址)。这实际上加强了使用 IPy 或套接字模块的需求。
      【解决方案4】:

      我认为在 Python 3.6 上要简单得多,因为已经包含了 ipaddress 模块:

      import ipaddress
      
          def is_ipv4(string):
              try:
                  ipaddress.IPv4Network(string)
                  return True
              except ValueError:
                  return False
      

      【讨论】:

      • 我认为最好用“除了 ipaddress.AddressValueError:”来捕捉实际错误
      • @JavierRuiz Python 3.8 为我提出了 ValueError 而不是 ipaddress.AddressValueError
      【解决方案5】:

      无需重新验证:

      def validip(ip):
          return ip.count('.') == 3 and  all(0<=int(num)<256 for num in ip.rstrip().split('.'))
      
      for i in ('123.233.42.12','3234.23.453.353','-2.23.24.234','1.2.3.4'):
          print i,validip(i)
      

      【讨论】:

      • 在求助re之前应该尝试这样的方法。
      • 如果抛出异常,最好默认返回false。例如'192.168.1.abc'
      【解决方案6】:

      你的正则表达式不检查字符串的结尾,所以它会匹配:

      123.45.67.89abc123boogabooga
      

      要解决此问题,请使用:

      '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$'
      

      (注意末尾的$)。

      最后,在 Python 中,通常的样式是使用 is not None 而不是 != None

      【讨论】:

        【解决方案7】:

        如果您要验证 IP 地址,我建议如下:

        import socket
        
        try:
            socket.inet_aton(addr)
            return True
        except socket.error:
            return False
        

        如果您只是想检查它的格式是否正确,那么您可能希望对所有 legal bases 进行检查(不仅仅是以 10 为基数的编号)。

        此外,IP 地址是否仅为 IPv4(没有一个是 IPv6),那么您只需查找有效地址并使用 split()(获取 IP 的单个 组件)和 @ 987654325@(用于比较的类型种姓)。有效 IPv4 规则的快速参考是here

        【讨论】:

          【解决方案8】:

          安装 netaddr 包

          sudo pip install netaddr
          

          然后你就可以这样做了

          >>> from netaddr import valid_ipv4
          >>> valid_ipv4('11.1.1.2') 
          True
          >>> valid_ipv4('11.1.1.a')
          False
          

          您还可以从该字符串创建一个 IPAddress 对象以及更多与 ip 相关的操作

          >>> from netaddr import IPAddress
          >>> ip = IPAddress('11.1.1.1')
          >>> [f for f in dir(ip) if '__' not in f]
          ['_module', '_set_value', '_value', 'bin', 'bits', 'format', 'info', 'ipv4', 'ipv6', 'is_hostmask', 'is_ipv4_compat', 'is_ipv4_mapped', 'is_link_local', 'is_loopback', 'is_multicast', 'is_netmask', 'is_private', 'is_reserved', 'is_unicast', 'key', 'netmask_bits', 'packed', 'reverse_dns', 'sort_key', 'value', 'version', 'words']
          

          【讨论】:

            【解决方案9】:

            此页面中的其他正则表达式答案将接受数字超过 255 的 IP。

            这个正则表达式可以避免这个问题:

            import re
            
            def validate_ip(ip_str):
                reg = r"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
                if re.match(reg, ip_str):
                    return True
                else:
                    return False
            

            【讨论】:

              【解决方案10】:

              如果你反复使用,你应该预编译正则表达式

              re_ip = re.compile('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$')
              # note the terminating $ to really match only the IPs
              

              然后使用

              if re_ip.match(st):
                  print '!IP'
              

              但是.. 是例如'111.222.333.444' 真的是 IP 吗?

              我会看看 netaddripaddr 库是否可以用于匹配 IP

              【讨论】:

                【解决方案11】:

                在内置库ipaddress中检查给定IP是否有效非常简单。您也可以使用掩码验证值。

                ip = '30.0.0.1'   #valid
                #ip = '300.0.0.0/8'  #invalid
                #ip = '30.0.0.0/8'   #valid
                #ip = '30.0.0.1/8'   #invalid
                #ip = 'fc00:da00::3402:69b1' #valid
                #ip = 'fc00:da00::3402:69b1/128' #valid
                #ip = 'fc00:da00::3402:69b1:33333' #invalid
                
                if ip.find('/') > 0:
                    try:
                        temp2 = ipaddress.ip_network(ip)
                        print('Valid IP network')        
                    except ValueError:
                        print('Invalid IP network, value error')
                else:        
                    try:
                        temp2 = ipaddress.ip_address(ip)
                        print('Valid IP')
                    except ValueError:
                        print('Invalid IP')
                

                注意:在 Python 3.4.3 中测试

                【讨论】:

                  【解决方案12】:

                  可以使用iptools。

                  import iptools
                  ipv4 = '1.1.1.1'
                  ipv6 = '5000::1'
                  iptools.ipv4.validate_ip(ipv4) #returns bool
                  iptools.ipv6.validate_ip(ipv6) #returns bool
                  

                  【讨论】:

                  • 简洁明了。为我工作。
                  【解决方案13】:

                  你可以通过编译让它更快一点:

                  expression = re.compile('^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$')
                  for st in strs:
                      if expression.match(st):
                         print 'IP!'
                  

                  【讨论】:

                    【解决方案14】:

                    我作弊并使用了其他人提交的多个答案的组合。我认为这是一段非常清晰和直接的代码。 ip_validation 应该返回 TrueFalse。此答案也仅适用于 IPv4 地址

                    import re
                    ip_match = re.match('^' + '[\.]'.join(['(\d{1,3})']*4) + '$', ip_input)
                    ip_validate = bool(ip_match)
                    if ip_validate:
                        ip_validate &= all(map(lambda n: 0 <= int(n) <= 255, ip_match.groups())
                    

                    【讨论】:

                      【解决方案15】:

                      这也适用于 ipv6 地址。

                      不幸的是它仅适用于 python3

                      import ipaddress
                      
                      def valid_ip(address):
                          try: 
                              print ipaddress.ip_address(address)
                              return True
                          except:
                              return False
                      
                      print valid_ip('10.10.20.30')
                      print valid_ip('2001:DB8::1')
                      print valid_ip('gibberish')
                      

                      【讨论】:

                        【解决方案16】:

                        我们不需要任何导入来执行此操作。这也工作得更快

                        def is_valid_ip(str_ip_addr):
                           """
                           :return: returns true if IP is valid, else returns False
                           """
                           ip_blocks = str(str_ip_addr).split(".")
                           if len(ip_blocks) == 4:
                               for block in ip_blocks:
                                   # Check if number is digit, if not checked before calling this function
                                   if not block.isdigit():
                                       return False
                                   tmp = int(block)
                                   if 0 > tmp > 255:
                                       return False
                               return True
                            return False
                        

                        【讨论】:

                          【解决方案17】:
                          #!/usr/bin/python
                          import sys
                          def check_ip(address):
                              part=address.split(".")
                              temp=True
                              if len(part) != 4:
                                      temp=False
                                      return temp
                              for p in part:
                                      if not 0<= int(p) <= 255:
                                              temp=False
                                              return temp
                                      else:
                                              temp=True
                              return temp
                          if __name__=="__main__":
                              print check_ip(sys.argv[1])
                          

                          使用某个名称保存代码 - check_ip.py 并以 python check_ip.py 192.168.560.25 运行它
                          注意:- 对于以下 IP 地址,上面的代码失败 -
                          023.65.029.33

                          【讨论】:

                          • 此代码是否适用于 Windows? File "C:\Python\Codes\check_ip.py", line 17 print check_ip(sys.argv[1]) ^ SyntaxError: invalid syntax
                          • @Sabrina 不确定..您可以验证它...可能是您身边的一些缩进错误...尝试输入代码而不是复制粘贴
                          【解决方案18】:

                          您可以尝试以下方法(程序可以进一步优化):

                          path = "/abc/test1.txt"
                          fh = open (path, 'r')
                          ip_arr_tmp = []
                          ip_arr = []
                          ip_arr_invalid = []
                          
                          for lines in fh.readlines():
                              resp = re.search ("([0-9]+).([0-9]+).([0-9]+).([0-9]+)", lines)
                              print resp
                          
                              if resp != None:
                                 (p1,p2,p3,p4) = [resp.group(1), resp.group(2), resp.group(3), resp.group(4)]       
                          
                                 if (int(p1) < 0 or int(p2) < 0 or int(p3) < 0 or int(p4) <0):
                                     ip_arr_invalid.append("%s.%s.%s.%s" %(p1,p2,p3,p4))
                          
                                 elif (int(p1) > 255 or int(p2) > 255 or int(p3) > 255 or int(p4) > 255):
                                      ip_arr_invalid.append("%s.%s.%s.%s" %(p1,p2,p3,p4))
                          
                                 elif (len(p1)>3 or len(p2)>3 or len(p3)>3 or len(p4)>3):
                                      ip_arr_invalid.append("%s.%s.%s.%s" %(p1,p2,p3,p4))
                          
                                 else:
                                     ip = ("%s.%s.%s.%s" %(p1,p2,p3,p4))
                                     ip_arr_tmp.append(ip)
                          
                          print ip_arr_tmp
                          
                          for item in ip_arr_tmp:
                              if not item in ip_arr:
                                 ip_arr.append(item)
                          
                          print ip_arr
                          

                          【讨论】:

                            【解决方案19】:

                            在 Python 3.* 中非常简单,这是一个实用函数,将检查 对于任何 ip、ipv4 或 ipv6 ,只需使用 Python 标准库 ipaddress — IPv4/IPv6 manipulation library

                            from ipaddress import ip_address, IPv4Address, IPv6Address, AddressValueError
                            
                            
                            def _is_valid_ip_address(ip, ipv_type: str = 'any') -> bool:
                                """Validates an ipd address"""
                                try:
                                    if ipv_type == 'any':
                                        ip_address(ip)
                                    elif ipv_type == 'ipv4':
                                        IPv4Address(ip)
                                    elif ipv_type == 'ipv6':
                                        IPv6Address(ip)
                                    else:
                                        raise NotImplementedError
                                except (AddressValueError, ValueError):
                                    return False
                                else:
                                    return True
                            
                            def run_tests():
                                ipv4 = '192.168.0.1'
                                ipv6 = '2001:db8::1000'
                                bad = "I AM NOT AN IP"
                                is_pv4 = _is_valid_ip_address(ipv4)
                                is_pv6 = _is_valid_ip_address(ipv6)
                                bad_ip = _is_valid_ip_address(bad)
                            
                                am_i_pv4 = _is_valid_ip_address(ipv6, ipv_type='ipv4')
                                am_i_pv6 = _is_valid_ip_address(ipv4, ipv_type='ipv6')
                                print(f'''
                                * is_pv4 -> {is_pv4}
                                * is_pv6 -> {is_pv6}
                                * bad_ip -> {bad_ip}
                                * am_i_pv4 -> {am_i_pv4}
                                * am_i_pv6 -> {am_i_pv6}
                                ''')
                            
                            
                            
                            if __name__ == '__main__':
                                run_tests()
                            

                            结果

                            * is_pv4 -> True
                            * is_pv6 -> True
                            * bad_ip -> False
                            * am_i_pv4 -> False
                            * am_i_pv6 -> False
                            

                            【讨论】:

                              猜你喜欢
                              • 2010-12-19
                              • 2022-03-03
                              • 2012-09-17
                              • 2018-04-03
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2014-07-25
                              相关资源
                              最近更新 更多