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

Question:

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? 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!'
Asked By: Tommy Morene

||

Answers:

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.</update>

It looks like you are trying to validate IP addresses. 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):

from IPy import IP
IP('127.0.0.1')

If the IP address is invalid it will throw an exception.

Or you could use 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.

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.

Answered By: Mark Byers

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.

Answered By: Greg Hewgill

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!'
Answered By: Matt Williamson

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 e.g. ‘111.222.333.444’ really the IP?

i’d look at netaddr or ipaddr libraries whether they can be used to match IPs

Answered By: mykhal

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. 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!-):

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

Answered By: Alex Martelli

If you are validating IP address I would suggest the following:

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

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). A quick reference to valid IPv4 rules is here.

Answered By: Jungle Hunter

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)
Answered By: Tony Veijalainen

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. Also this answer only works for IPv4 addresses

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())
Answered By: Barmaley

If you use Python3, you can use ipaddress module 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
Answered By: zakiakhmad

Install netaddr package

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

>>> 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']
Answered By: Prem Anand

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
Answered By: IAmSurajBobade

Very simple to check whether given IP is valid or not using in built library ipaddress. 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

Answered By: IRSHAD

This works for ipv6 addresses as well.

Unfortunately it Works for python3 only

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')
Answered By: Deepak

Other regex answers in this page will accept an IP with a number over 255.

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
Answered By: Lucas Coelho
#!/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
Note:- Above code fails for the below ip address-
023.65.029.33

Answered By: Yogesh Jilhawar

On Python 3.6 I think is much simpler as ipaddress module is already included:

import ipaddress

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

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
Answered By: python_student

iptools can be used.

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

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

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
Answered By: Federico Baù

I needed a solution for IPV4 addresses on Python 2.7 (old project at work)

  • socket.inet_aton is more permissive than I’d like.
  • 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:
%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():
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)
Answered By: Jay
from ipaddress import ip_address, IPv4Address

def validIPAddress(IP: str) -> str:
    try:
        return "IPv4" if type(ip_address(IP)) is IPv4Address else "IPv6"
    except ValueError:
        return "Invalid"

if __name__ == '__main__' :
        
    # Enter the Ip address
    Ip = "192.168.0.1"
    print(validIPAddress(Ip))

    Ip = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
    print(validIPAddress(Ip))

    Ip = "256.32.555.5"
    print(validIPAddress(Ip))

    Ip = "250.32:555.5"
    print(validIPAddress(Ip))

Output :

IPv4
IPv6
Invalid
Invalid
Answered By: rmaleki
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.