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

Viewed 128277

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

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

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

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

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

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

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

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

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