简体   繁体   English

检查字符串是否与 python 中的 IP 地址模式匹配?

[英]check if a string matches an IP address pattern in python?

What is the fastest way to check if a string matches a certain pattern?检查字符串是否与特定模式匹配的最快方法是什么? Is regex the best way?正则表达式是最好的方法吗?

For example, I have a bunch of strings and want to check each one to see if they are a valid IP address (valid in this case meaning correct format), is the fastest way to do this using regex?例如,我有一堆字符串,想检查每个字符串是否是有效的 IP 地址(在这种情况下有效意味着格式正确),是使用正则表达式执行此操作的最快方法吗? Or is there something faster with like string formatting or something.或者是否有更快的字符串格式或其他东西。

Something like this is what I have been doing so far:到目前为止,我一直在做这样的事情:

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

update : The original answer bellow is good for 2011, but since 2012, one is likely better using Python's ipaddress stdlib module - besides checking IP validity for IPv4 and IPv6, it can do a lot of other things as well.更新:下面的原始答案适用于 2011 年,但自 2012 年以来,使用 Python 的ipaddress stdlib 模块可能会更好 - 除了检查 IPv4 和 IPv6 的 IP 有效性之外,它还可以做很多其他事情。 </update>

It looks like you are trying to validate IP addresses .看起来您正在尝试验证 IP 地址 A regular expression is probably not the best tool for this.正则表达式可能不是最好的工具。

If you want to accept all valid IP addresses (including some addresses that you probably didn't even know were valid) then you can use IPy (Source) :如果您想接受所有有效的 IP 地址(包括一些您甚至可能不知道有效的地址),那么您可以使用IPy (Source)

from IPy import IP
IP('127.0.0.1')

If the IP address is invalid it will throw an exception.如果 IP 地址无效,它将引发异常。

Or you could use socket (Source) :或者你可以使用socket (Source)

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

If you really want to only match IPv4 with 4 decimal parts then you can split on dot and test that each part is an integer between 0 and 255.如果您真的只想将 IPv4 与 4 个小数部分匹配,那么您可以在点上拆分并测试每个部分是 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

Note that your regular expression doesn't do this extra check.请注意,您的正则表达式不会执行此额外检查。 It would accept 999.999.999.999 as a valid address.它将接受999.999.999.999作为有效地址。

If you use Python3 , you can use ipaddress module http://docs.python.org/py3k/library/ipaddress.html .如果您使用Python3 ,则可以使用ipaddress模块http://docs.python.org/py3k/library/ipaddress.html Example:例子:

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

I'm normally the one of the very few Python experts who steadfastly defends regular expressions (they have quite a bad reputation in the Python community), but this is not one of those cases -- accepting (say) '333.444.555.666' as an "IP address" is really bad, and if you need to do more checks after matching the RE, much of the point of using a RE is lost anyway.我通常是为数不多的坚定捍卫正则表达式的 Python 专家之一(他们在 Python 社区中的名声很差),但这不是其中一种情况——接受(比如) '333.444.555.666'作为“IP 地址”真的很糟糕,如果您需要在匹配 RE 后进行更多检查,那么无论如何使用 RE 的大部分意义都将丢失。 So, I second @Mark's recommendations heartily: IPy for generality and elegance (including support of IPv6 if you want!), string operations and int checks if you only need IPv4 (but, think twice about that limitation, and then think one more -- IPv6's time has way come!-):所以,我衷心支持@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

I'd far rather do that than a convoluted RE to match only numbers between 0 and 255!-)我宁愿这样做,也不愿使用复杂的 RE 只匹配 0 到 255 之间的数字!-)

On Python 3.6 I think is much simpler as ipaddress module is already included:在 Python 3.6 上,我认为要简单得多,因为已经包含了 ipaddress 模块:

import ipaddress

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

One more validation without re:无需重新验证的另一项验证:

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)

Your regular expression doesn't check for the end of the string, so it would match:您的正则表达式不会检查字符串的结尾,因此它将匹配:

123.45.67.89abc123boogabooga

To fix this, use:要解决此问题,请使用:

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

(note the $ at the end). (注意末尾的$ )。

Finally, in Python the usual style is to use is not None instead of != None .最后,在 Python 中,通常的样式是使用is not None而不是!= None

If you are validating IP address I would suggest the following:如果您正在验证 IP 地址,我建议您执行以下操作:

import socket

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

If you just want to check if it is in the right format then you would want to do it for all legal bases (not just base 10 numbering).如果您只想检查它是否采用正确的格式,那么您可能希望针对所有合法基础(而不仅仅是以 10 为基础的编号)进行检查。

Also, are the IP address IPv4 only (and none are IPv6) then you could just look up what valid address are and use split() (to get individual components of the IP) and int() (to type-caste for comparison).此外,IP 地址是否仅为 IPv4(没有 IPv6),那么您可以查找有效地址并使用split() (获取 IP 的各个组件)和int() (输入种姓进行比较) . A quick reference to valid IPv4 rules is here . 此处为有效 IPv4 规则的快速参考。

Install netaddr package安装 netaddr 包

sudo pip install netaddr

And then you can do this然后你可以这样做

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

Also you create a IPAddress object from that string and a lot more ip related operations您还可以从该字符串创建一个 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']

Other regex answers in this page will accept an IP with a number over 255.此页面中的其他正则表达式答案将接受数字超过 255 的 IP。

This regex will avoid this problem:这个正则表达式将避免这个问题:

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

you should precompile the regexp, if you use it repeatedly你应该预编译正则表达式,如果你重复使用它

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

then use然后使用

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

but.. is eg '111.222.333.444' really the IP?但是......例如'111.222.333.444'真的是IP吗?

i'd look at netaddr or ipaddr libraries whether they can be used to match IPs我会查看netaddripaddr库是否可以用于匹配 IP

Very simple to check whether given IP is valid or not using in built library ipaddress .使用内置库ipaddress非常简单地检查给定的 IP 是否有效。 You can also validate using mask value.您还可以使用掩码进行验证

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

Note: Tested in Python 3.4.3注意:在 Python 3.4.3 中测试

I cheated and used combination of multiple answers submitted by other people.我作弊并使用了其他人提交的多个答案的组合。 I think this is pretty clear and straight forward piece of code.我认为这是一段非常清晰和直接的代码。 ip_validation should return True or False . ip_validation应该返回TrueFalse Also this answer only works for IPv4 addresses此外,此答案仅适用于 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())

You can make it a little faster by compiling it:你可以通过编译让它更快一点:

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

We do not need any import to do this.我们不需要任何导入来做到这一点。 This also works much faster这也工作得更快

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

This works for ipv6 addresses as well.这也适用于 ipv6 地址。

Unfortunately it Works for python3 only不幸的是它仅适用于 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')
#!/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])

Save the code with some name say- check_ip.py and run it as python check_ip.py 192.168.560.25将代码保存为某个名称check_ip.py并将其作为python check_ip.py 192.168.560.25运行
Note:- Above code fails for the below ip address-注意:-对于以下 ip 地址,以上代码失败-
023.65.029.33

You may try the following (the program can be further optimized):您可以尝试以下操作(程序可以进一步优化):

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

iptools can be used.可以使用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

In Python 3.* is very simple, this is a utily function that will check for any ip, ipv4 or ipv6 , that's just using the Python Standard Library ipaddress — IPv4/IPv6 manipulation library在 Python 3.* 中非常简单,这是一个实用的函数,可以检查任何 ip、ipv4 或 ipv6,这只是使用 Python 标准库ipaddress — IPv4/IPv6 操作库

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

The result结果

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

I needed a solution for IPV4 addresses on Python 2.7 (old project at work)我需要 Python 2.7 上的 IPV4 地址解决方案(工作中的旧项目)

  • socket.inet_aton is more permissive than I'd like. socket.inet_aton比我想要的更宽松。
  • Don't want/like to use regex.不想/喜欢使用正则表达式。

This works for me:这对我有用:

def is_ipv4_address(ip_string):

    ip_parts = ip_string.split('.')
    return len(ip_parts) == 4 and all(part.isdigit() for part in ip_parts) and all(255 >= int(part) >=0 for part in ip_parts)
  • int(part) in range(0,255) looks nicer than 255 >= int(part) >=0 , but is slower: int(part) in range(0,255)看起来比255 >= int(part) >=0更好,但更慢:
%timeit 5 in range(0,255)
113 ns ± 1.27 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)

%timeit 255 >= 5 >= 0
30.5 ns ± 0.276 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
  • On Python 3.10/Linux, this works faster than ipaddress.ip_address() :在 Python 3.10/Linux 上,这比ipaddress.ip_address()更快:
import ipaddress

ip = '192.168.0.0'

%timeit ipaddress.ip_address(ip)
2.15 µs ± 21.5 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

%timeit is_ipv4_address(ip)
1.18 µs ± 24.6 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

您可以使用正则表达式: http : //www.regular-expressions.info/python.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM