26

I'm trying to make a test for checking whether a sys.argv input matches the RegEx for an IP address...

As a simple test, I have the following...

import re

pat = re.compile("\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}")
test = pat.match(hostIP)
if test:
   print "Acceptable ip address"
else:
   print "Unacceptable ip address"

However when I pass random values into it, it returns "Acceptable IP address" in most cases, except when I have an "address" that is basically equivalent to \d+.

martineau
  • 119,623
  • 25
  • 170
  • 301
MHibbin
  • 1,135
  • 5
  • 19
  • 31
  • 5
    Are you willing to accept 999.999.999.999 as "valid" IP address? :) – Maria Zverina Jun 29 '12 at 15:15
  • See http://stackoverflow.com/questions/319279/how-to-validate-ip-address-in-python?lq=1 and http://stackoverflow.com/questions/10191442/check-hostnames-and-ip-addresses-v4-and-v6-using-a-single-python-regex?rq=1 – belacqua Jun 29 '12 at 15:17

14 Answers14

47

Using regex to validate IP address is a bad idea - this will pass 999.999.999.999 as valid. Try this approach using socket instead - much better validation and just as easy, if not easier to do.

import socket

def valid_ip(address):
    try: 
        socket.inet_aton(address)
        return True
    except:
        return False

print valid_ip('10.10.20.30')
print valid_ip('999.10.20.30')
print valid_ip('gibberish')

If you really want to use parse-the-host approach instead, this code will do it exactly:

def valid_ip(address):
    try:
        host_bytes = address.split('.')
        valid = [int(b) for b in host_bytes]
        valid = [b for b in valid if b >= 0 and b<=255]
        return len(host_bytes) == 4 and len(valid) == 4
    except:
        return False
Maria Zverina
  • 10,863
  • 3
  • 44
  • 61
  • Yes ... you could write a write a horrendous regex that matches "0" to "255" but it's probably better to avoid it :) – Maria Zverina Jun 29 '12 at 15:20
  • 1
    +1 from me too for this approach (upvoted an hour ago or so :) – Levon Jun 29 '12 at 17:32
  • 4
    The socket approach returns true for address='0.33'! – Ritesh Sep 20 '13 at 23:23
  • 3
    @Maria - I believe the key here is 'matching' IP addresses, in like: "Here is this 10 Terabyte file/DB, **match** or _list_ the IP addresses you can find", as opposed to "_create a function that receives a string and returns whether it is an IP address_", hence the solution to me is to use a well-crafted regex, as much as we _hate_ them.. – Speedbird Mar 08 '14 at 04:31
  • 1
    @Speedbird - OP specified checking IP address in sys.argv. Hence I believe regex is not the right choice. I agree that if you need to process a large file/DB, regex would be a good choice though. :) – Maria Zverina Aug 01 '14 at 15:39
  • @MariaZverina As a formality, the `return True` should be outside of the `try` block. Won't really make a difference, just me being a little pedantic. :) – anon582847382 Nov 01 '14 at 22:01
  • IPv6 is missed completely. Otherwise `socket` approach is good but just to note, in the parsing approach, 127.1 is identified as invalid ip, whereas it is valid. – 0xc0de Apr 29 '16 at 08:24
  • The most elegant approach IMHO. Regexes for IPs are ugly and full of corner cases. Suggestion: condense 3 lines into 1, shorter *and* easier to read: `return 4 == len(octets) == len([b for b in octets if 0 <= int(b) <= 255])` – MestreLion Jun 06 '22 at 02:47
  • The socket approach validates also "22". This is outright dangerous. The ipaddress method below makes more sense. – Janne Paalijarvi Oct 06 '22 at 16:17
  • This idea passes some addresses which might be better off rejected, e.g. `192.168.0007.001` passes - it must convert each part to a number and not care about leading zeros... but I wonder if it gets confused by octal notation, e.g. `192.168.010.001` is the third part a 10 or an 8? – user9645 Nov 29 '22 at 17:28
28

You have to modify your regex in the following way

pat = re.compile("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$")

that's because . is a wildcard that stands for "every character"

DonCallisto
  • 29,419
  • 9
  • 72
  • 100
  • Also to make sure the string is exactly as provided you could add `^` to be beginning and `$` to the end. Otherwise it possible matches a string like `10.0.0.1:1234` where you don't want it. – javex Jun 29 '12 at 14:55
  • OMG...FFS!!! such a "school-boy error"... I was actually helping someone the other day with regex and "."... GHHHH! ... I was set on it being a python issue! Thanks very much – MHibbin Jun 29 '12 at 15:01
  • 2
    BTW: prefix the string with r also, it's a good habit: `r"^\d{1,3}..."` – Ned Batchelder Jun 29 '12 at 15:06
  • 5
    Guys this doesn't work.. test it before giving "the green tick". 255.255.255.256 fails, and so on.. – FrancescoN Jan 24 '14 at 15:09
  • 2
    This doesn't work. it also filters this - 2.16.840.1 , which can't be an ip – Sheesh Mohsin May 30 '15 at 16:48
  • We all know that ipv4 will have three `.`s and 4 numbers, is it possible to simplify it in this regex to something like `pat = re.compile("^\d{1,3}(\.\d{1,3}){3}$")` – ZDunker Aug 10 '17 at 01:12
  • @MHibbin people who comment is right: please, unmark this as accepted answer so I can delete it – DonCallisto Sep 26 '17 at 10:09
  • 3
    It *will* match IPv4 addresses. It will also match things that look like IPv4 addresses but aren't, so it's not an IPv4 address validator. But it is still valuable for parsing IPv4 addresses in places like Apache log files, where retrieving the address field is the goal, not validating it. – President James K. Polk Aug 30 '19 at 13:46
16

regex for ip v4:

^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$

otherwise you take not valid ip address like 999.999.999.999, 256.0.0.0 etc

Manos Nikolaidis
  • 21,608
  • 12
  • 74
  • 82
burning_LEGION
  • 13,246
  • 8
  • 40
  • 52
  • wow! I think I will stick with the sockets method, thanks though.. I will actually take note of this... I was wondering what it would look like. :-) – MHibbin Jul 01 '12 at 09:44
  • Cool. If use not in Python but PRCE it can be a bit shorter using subroutines: `^((25[0-5]|2[0-4][0-9]|[01]?[0-9]{1,2})\.){3}(?2)$` https://regex101.com/r/sE3hK5/1 – Alexander Trakhimenok Mar 11 '16 at 14:05
  • I think you have an error after the first group. You are escaping \ instead of dot and you let it take any kind of character that way. Here is the fix I made: https://regexper.com/#%5E%28%2825%5B0-5%5D%7C2%5B0-4%5D%5B0-9%5D%7C%5B01%5D%3F%5B0-9%5D%5B0-9%5D%3F%29%5C.%29%7B3%7D%2825%5B0-5%5D%7C2%5B0-4%5D%5B0-9%5D%7C%5B01%5D%3F%5B0-9%5D%5B0-9%5D%3F%29%24 – NFSpeedy Oct 28 '20 at 08:25
  • this looks much better than the valid answer, but ips adresses with leading zeros will be falsely match e.g. 001.001.001.1 which is invalid when using in typically libraries – cinatic Aug 13 '21 at 18:55
13

I came across the same situation, I found the answer with use of socket library helpful but it doesn't provide support for ipv6 addresses. Found a better way for it:

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'))
Deepak
  • 173
  • 3
  • 8
3

You are trying to use . as a . not as the wildcard for any character. Use \. instead to indicate a period.

BlackVegetable
  • 12,594
  • 8
  • 50
  • 82
0
def ipcheck():
# 1.Validate the ip adderess
input_ip = input('Enter the ip:')
flag = 0

pattern = "^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$"
match = re.match(pattern, input_ip)
if (match):
    field = input_ip.split(".")
    for i in range(0, len(field)):
        if (int(field[i]) < 256):
            flag += 1
        else:
            flag = 0
if (flag == 4):
    print("valid ip")
else:
    print('No match for ip or not a valid ip')
0
import re
ipv=raw_input("Enter an ip address")
a=ipv.split('.')
s=str(bin(int(a[0]))+bin(int(a[1]))+bin(int(a[2]))+bin(int(a[3])))
s=s.replace("0b",".")
m=re.search('\.[0,1]{1,8}\.[0,1]{1,8}\.[0,1]{1,8}\.[0,1]{1,8}$',s)
if m is not None:
    print "Valid sequence of input"
else :
    print "Invalid input sequence"

Just to keep it simple I have used this approach. Simple as in to explain how really ipv4 address is evaluated. Checking whether its a binary number is although not required. Hope you like this.

0
str = "255.255.255.255"
print(str.split('.'))

list1 = str.split('.')

condition=0

if len(list1)==4:
    for i in list1:
        if int(i)>=0 and int(i)<=255:
            condition=condition+1

if condition!=4:
    print("Given number is not IP address")
else:
    print("Given number is valid IP address")
Jee Mok
  • 6,157
  • 8
  • 47
  • 80
0

If you really want to use RegExs, the following code may filter the non-valid ip addresses in a file, no matter the organiqation of the file, one or more per line, even if there are more text (concept itself of RegExs) :

def getIps(filename):
    ips = []
    with open(filename) as file:
        for line in file:
            ipFound = re.compile("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$").findall(line)
            hasIncorrectBytes = False
            try:
                    for ipAddr in ipFound:
                        for byte in ipAddr:
                            if int(byte) not in range(1, 255):
                                hasIncorrectBytes = True
                                break
                            else:
                                pass
                    if not hasIncorrectBytes:
                        ips.append(ipAddr)
            except:
                hasIncorrectBytes = True

    return ips
Unguest
  • 21
  • 3
0
re.sub('((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])', '--', '127.0.0.1')

With this regular expression, only numbers from 0 to 255 could compose the address. It also handles leading zeros, so 127.00.0.1 would no pass.

Diogo Melo
  • 1,735
  • 3
  • 20
  • 29
-1

IP address uses following authentication :

  1. 255 ---> 250-255
  2. 249 ---> 200-249
  3. 199 ---> 100-199
  4. 99 ---> 10-99
  5. 9 ---> 1-9

    import re    
    k = 0
    while k < 5 : 
        i = input("\nEnter Ip address : ")
        ip = re.match("^([1][0-9][0-9].|^[2][5][0-5].|^[2][0-4][0-9].|^[1][0-9][0-9].|^[0-9][0-9].|^[0-9].)([1][0-9][0-9].|[2][5][0-5].|[2][0-4][0-9].|[1][0-9][0-9].|[0-9][0-9].|[0-9].)([1][0-9][0-9].|[2][5][0-5].|[2][0-4][0-9].|[1][0-9][0-9].|[0-9][0-9].|[0-9].)([1][0-9][0-9]|[2][5][0-5]|[2][0-4][0-9]|[1][0-9][0-9]|[0-9][0-9]|[0-9])$",i)
        k = k + 1 
        if ip:
            print ("\n=====================")
            print ("Valid IP address")
            print ("=====================")
            break
        else :
            print ("\nInvalid IP")
    else :
        print ("\nAllowed Max 5 times")
    

Reply me if you have doubt?

Giacomo1968
  • 25,759
  • 11
  • 71
  • 103
-1
import re

st1 = 'This is my IP Address10.123.56.25 789.356.441.561 127 255 123.55 192.168.1.2.3 192.168.2.2 str1'

Here my valid IP Address is only 192.168.2.2 and assuming 10.123.56.25 is not a valid one as it is combined with some string and 192.168.1.2.3 not valid.

pat = r'\s(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\s|$))'

match = re.search(pat,st1)

print match.group()

================ RESTART: C:/Python27/Srujan/re_practice.py ================
192.168.2.2 

This will grep the exact IP Address, we can ignore any pattern look like an IP Address but not a valid one. Ex: 'Address10.123.56.25', '789.356.441.561' '192.168.1.2.3'.

Please comment if any modifications are required.

John Moutafis
  • 22,254
  • 11
  • 68
  • 112
srujan kumar
  • 171
  • 1
  • 7
-2

This works for python 2.7:

import re
a=raw_input("Enter a valid IP_Address:")
b=("[0-9]+"+".")+"{3}"
if re.match(b,a) and b<255:
    print "Valid"
else:
    print "invalid"
Timothy G.
  • 6,335
  • 7
  • 30
  • 46
-2

""" regex for finding valid ip address """

import re


IPV4 = re.fullmatch('([0-2][0-5]{2}|\d{2}|\d).([0-2][0-5]{2}|\d{2}|\d).([0-2][0-5]{2}|\d{2}|\d).([0-2][0-5]{2}|\d{2}|\d)', '100.1.1.2')

if IPV4:
    print ("Valid IP address")

else:
    print("Invalid IP address")