I don't even know what was going wrong, but as soon as I'd refactored it into
this it seemed to work:
import re
ip_num_pat = r"[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]"
pattern = re.compile(r'(?:({0})\.){{3}}({0})'.format(ip_num_pat))
ip_addrs = [
'17.255.16.45', '255.255.255.255', '0.0.0.0', '0.14.255.14',
'2555.2564.0.3', '0.3.255']
for ip in ip_addrs:
if pattern.match(ip):
print(ip, 'ok')
else:
print(ip, 'nope')
In general it can be easier to keep track of things like this by breaking them
up into smaller parts. I think probably the last block was wrong.
Also, note that I have changed your code to use .match
, not .search
.
This is crucial, because otherwise you will match things like 01.2.3.4
.
But, as others have said, a much easier approach would look something like this:
ip_addrs = [
'17.255.16.45', '255.255.255.255', '0.0.0.0', '0.14.255.14',
'2555.2564.0.3', '0.3.255', '03.1.2.3']
def is_ip(addr):
try:
component_strings = addr.split(".")
if any(i.startswith("0") and i != "0" for i in component_strings):
raise ValueError("Components cannot start with 0")
components = [int(i) for i in component_strings]
if len(components) != 4:
raise ValueError("Need 4 parts for an IPv4 address")
if any(not 0 <= i < 256 for i in components):
raise ValueError("Components should be in range 0, ..., 255")
return True
except ValueError:
return False
for ip in ip_addrs:
if is_ip(ip):
print(ip, 'ok')
else:
print(ip, 'nope')