IPv6 Regex
Full-form and ::-compressed IPv6 matching per RFC 4291 — the library's honest inversion, CI-verified rows, live tester preloaded.
Pattern variants
Pragmatic
/^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$/i
What it matches
The full, uncompressed form: eight colon-separated groups of 1-4 hex digits.
What it deliberately doesn't
Every ::-compressed form (::1 fails), IPv4-mapped addresses and zone indices.
Strict
/^(?:(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,7}:|(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}|(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}|(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}|(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}|[0-9a-f]{1,4}:(?::[0-9a-f]{1,4}){1,6}|:(?:(?::[0-9a-f]{1,4}){1,7}|:))$/i
What it matches
Common forms including a single :: compression at any position, per RFC 4291.
What it deliberately doesn't
IPv4-embedded forms (::ffff:192.0.2.128), zone indices (%eth0) and bracketed URL syntax.
Verified vectors
| Input | Pragmatic | Strict | Note |
|---|---|---|---|
"2001:0db8:0000:0000:0000:8a2e:0370:7334" | ✓ matches | ✓ matches | |
"2001:db8:0:0:0:8a2e:370:7334" | ✓ matches | ✓ matches | full form with short groups |
"2001:db8::8a2e:370:7334" | ✗ no match | ✓ matches | :: compression — outside the full-form pragmatic |
"::1" | ✗ no match | ✓ matches | loopback |
"::" | ✗ no match | ✓ matches | the unspecified address |
"fe80::0202:b3ff:fe1e:8329" | ✗ no match | ✓ matches | link-local with compression |
"fe80::1%eth0" | ✗ no match | ✗ no match | zone index — deliberately out |
"::ffff:192.0.2.128" | ✗ no match | ✗ no match | IPv4-mapped form — deliberately out |
"2001:db8::1::2" | ✗ no match | ✗ no match | :: may appear only once |
"12345::1" | ✗ no match | ✗ no match | five-digit group |
"2001:db8:8a2e:370" | ✗ no match | ✗ no match | too few groups without :: |
"GGGG::1" | ✗ no match | ✗ no match | not hex |
Usage by language
JavaScript
Machine-verified/^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$/i
/^(?:(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,7}:|(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}|(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}|(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}|(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}|[0-9a-f]{1,4}:(?::[0-9a-f]{1,4}){1,6}|:(?:(?::[0-9a-f]{1,4}){1,7}|:))$/i
Python
Machine-verifiedre.compile(r"^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$", re.IGNORECASE)
re.compile(r"^(?:(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,7}:|(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}|(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}|(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}|(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}|[0-9a-f]{1,4}:(?::[0-9a-f]{1,4}){1,6}|:(?:(?::[0-9a-f]{1,4}){1,7}|:))$", re.IGNORECASE)
Java
Syntax-reviewed — not machine-verifiedPattern.compile("^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$", Pattern.CASE_INSENSITIVE)
Pattern.compile("^(?:(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,7}:|(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}|(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}|(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}|(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}|[0-9a-f]{1,4}:(?::[0-9a-f]{1,4}){1,6}|:(?:(?::[0-9a-f]{1,4}){1,7}|:))$", Pattern.CASE_INSENSITIVE)
Go
Syntax-reviewed — not machine-verifiedregexp.MustCompile(`(?i)^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$`)
regexp.MustCompile(`(?i)^(?:(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,7}:|(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}|(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}|(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}|(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}|[0-9a-f]{1,4}:(?::[0-9a-f]{1,4}){1,6}|:(?:(?::[0-9a-f]{1,4}){1,7}|:))$`)
C#
Syntax-reviewed — not machine-verifiednew Regex(@"^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$", RegexOptions.IgnoreCase)
new Regex(@"^(?:(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,7}:|(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}|(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}|(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}|(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}|[0-9a-f]{1,4}:(?::[0-9a-f]{1,4}){1,6}|:(?:(?::[0-9a-f]{1,4}){1,7}|:))$", RegexOptions.IgnoreCase)
PHP
Syntax-reviewed — not machine-verified'/^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$/i'
'/^(?:(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,7}:|(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}|(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}|(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}|(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}|[0-9a-f]{1,4}:(?::[0-9a-f]{1,4}){1,6}|:(?:(?::[0-9a-f]{1,4}){1,7}|:))$/i'
Caveats
- The full RFC 4291 grammar (IPv4-embedded forms, zone indices) is deliberately out of scope — use inet_pton or net.ParseIP for total coverage.
- :: may appear at most once (RFC 5952); both variants reject double compression.
Related patterns
Do it offline:$ grep -E -i '^([0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$' addresses.txt
How to use it
- Match machine-generated, uncompressed addresses — the kind packet dumps and routing tables print — with the compact full-form line.
- Accept human-typed shorthand like ::1 or fe80:: with strict, whose alternation covers a single compression at every position.
- For guaranteed coverage of every legal form, follow the regex with inet_pton or net.ParseIP once the obvious junk is filtered.
IPv6 arrives in layers: eight colon-separated hex groups written out, plus a :: shorthand swallowing runs of zero groups. The pragmatic pattern pins the full form, so ::1 fails it; strict adds the compression grammar branch by branch per RFC 4291. Zone indices and IPv4-mapped forms stay outside both; twelve CI-verified vectors document each choice.
Examples
^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$pattern /^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$/i
2001:0db8:0000:0000:0000:8a2e:0370:7334 ✓ matches
2001:db8:0:0:0:8a2e:370:7334 ✓ matches
2001:db8::8a2e:370:7334 ✗ no match
GGGG::1 ✗ no matchGroups may shrink to one digit but all eight must appear — the compressed third row needs the strict variant, and G is simply not hex.
^(?:(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,7}:|(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}|(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}|(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}|(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}|[0-9a-f]{1,4}:(?::[0-9a-f]{1,4}){1,6}|:(?:(?::[0-9a-f]{1,4}){1,7}|:))$pragmatic /^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$/i
strict /^(?:(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,7}:|(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}|(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}|(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}|(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}|[0-9a-f]{1,4}:(?::[0-9a-f]{1,4}){1,6}|:(?:(?::[0-9a-f]{1,4}){1,7}|:))$/i
fe80::0202:b3ff:fe1e:8329 pragmatic ✗ no match strict ✓ matches
:: pragmatic ✗ no match strict ✓ matches
12345::1 pragmatic ✗ no match strict ✗ no matchStrict accepts more than pragmatic here — the library's one inversion — because these shorthands are compressions the full form cannot spell. Five-digit groups stay out of both: hex groups carry four digits at most.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
The last word belongs to inet_pton
IPv4-embedded addresses like ::ffff:192.0.2.128 and zone-indexed forms are real IPv6 both variants refuse on purpose — the whole RFC 4291 grammar in one pattern is where regex stops paying rent. System parsers exist for the total case.
Common errors
Invalid regular expression: /^(?:\p{HexDigit}{1,4}:){7}\p{HexDigit}{1,4}$/u: Invalid property name- The Unicode property for hex digits is spelled \p{Hex_Digit}, underscore included, so V8 refuses the name under the u flag. Nastier without u: \p degrades to literal p and the pattern silently matches nothing.
FAQ
Why does ::1 fail the pragmatic pattern?
Because ::1 is shorthand — the loopback's full spelling 0:0:0:0:0:0:0:1 passes. Pragmatic pins the eight-group form; take strict when compressed input is legitimate, as human-typed data usually is.
Do these patterns accept URL hosts like [::1]:8080?
No — URL syntax brackets the address and appends a port; both fail at the anchors. Strip brackets and port before matching, or validate whole links on the URL page.
Why allow uppercase hex when lowercase is recommended?
The i flag accepts both cases while RFC 5952 recommends lowercase output — matching stays liberal, emission canonical. Normalize to lowercase when storing or comparing addresses as text.