C.W.K.
Stream
Lesson 03 of 12 · published

IP Address Validation

~8 min · ip, validation

Level 0Pattern-Curious
0 XP0/90 lessons0/15 achievements
0/100 XP to next level100 XP to go0% complete

The naive pattern

An IPv4 address is four numbers separated by dots: \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}. With anchors for validation: ^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$.

This accepts 999.999.999.999 which isn't a real IP. Each octet is 0-255.

The strict pattern

Each octet 0-255, expressed in regex:

(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)

Reading: 25[0-5] (250-255), OR 2[0-4]\d (200-249), OR 1\d\d (100-199), OR [1-9]?\d (0-99 with optional leading digit).

Full IPv4 with anchors:

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

Ugly but correct.

Or — let the standard library do it

For actual validation, use the IP parsing library: Python ipaddress.ip_address(s). It handles IPv4, IPv6, CIDR notation, and edge cases the regex doesn't. The regex is for FINDING IP-shaped strings; the library is for VALIDATING them.

IPv6 — don't even try

IPv6 has 8 groups of 4 hex digits, with multiple compression forms (::, dotted-quad embedded). The regex is over 100 characters and still doesn't catch all valid forms. Use ipaddress in Python, net.ParseIP in Go.

Code

IP patterns·python
import re

# Naive — finds IP-shaped strings, doesn't validate octet range
IP_NAIVE = re.compile(r'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b')
re.findall(IP_NAIVE, 'server at 192.168.1.1 and 999.999.999.999')
# ['192.168.1.1', '999.999.999.999']  — both 'match'

# Strict — each octet 0-255
OCTET = r'(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)'
IP_STRICT = re.compile(rf'^{OCTET}\.{OCTET}\.{OCTET}\.{OCTET}$')

bool(IP_STRICT.fullmatch('192.168.1.1'))      # True
bool(IP_STRICT.fullmatch('999.999.999.999'))  # False
bool(IP_STRICT.fullmatch('256.0.0.1'))        # False

# Best practice: extract with regex, validate with library
import ipaddress
for candidate in re.findall(IP_NAIVE, 'log: 192.168.1.1 and 999.999.999.999'):
    try:
        addr = ipaddress.ip_address(candidate)
        print(f'{addr} valid')
    except ValueError:
        print(f'{candidate} not a real IP')
# 192.168.1.1 valid
# 999.999.999.999 not a real IP

External links

Exercise

Write a script that takes a log file, extracts every IP-shaped string, and prints only the ones that are real IPs (using ipaddress.ip_address). Run it on a small log to see the difference between extraction and validation.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.