Quick answer
The regex for an IPv4 address is ^(?:(?: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)$. Each octet alternative covers part of the 0–255 range (250–255, 200–249, 100–199 and 0–99), so 256 and leading zeros like 01 are rejected. It matches 192.168.1.1 and 255.255.255.255. Use your language's IP parser when you also need to know whether the address is private or reserved.
- Tested examples
- Token-by-token breakdown
- Code in 5 languages
- Live tester
How to use the IPv4 address regex
- 1Copy the pattern with Copy pattern in the tester, or take a ready-made snippet for your language from the code section below.
- 2Check the sample lines in Test string: every line the IPv4 address regex accepts is highlighted, rejected lines stay plain.
- 3Paste your own values one per line to see which pass, and read Explanation for what each part of the pattern does.
- 4Open the Code tab for JavaScript, Python, Go, C#, PHP or Dart with the pattern translated and escaped.
- 5Validate again on the server: client-side checks give users quick feedback, not security.
How does the IPv4 address regex work?
Read it left to right. Each piece below matches one part of the input:
25[0-5]250 to 255.|2[0-4]\dor 200 to 249.|1\d\dor 100 to 199.|[1-9]?\dor 0 to 99, with no leading zero (so 01 and 007 fail).(?:…\.){3}Three octets, each followed by a dot.(?:…)$The fourth octet, then the end of the string.
Which strings does the IPv4 address regex match?
The whole input must match, from the first character to the last. Every row below is checked against the pattern by our automated test suite before each release.
| Input | Matches? | Why |
|---|---|---|
192.168.1.1 | Yes | A private home-network address. |
8.8.8.8 | Yes | Single-digit octets. |
10.0.0.255 | Yes | Zero and 255 are valid octets. |
255.255.255.255 | Yes | The highest address. |
0.0.0.0 | Yes | The lowest (it means "any address" in server configs). |
256.1.1.1 | No | 256 is out of range. |
192.168.1 | No | Only three octets. |
192.168.01.1 | No | Leading zeros are rejected: some parsers read them as octal. |
1.2.3.4.5 | No | Five octets. |
192.168.1.-1 | No | No negative numbers. |
192.168.1.1 | No | Leading space: trim input first. |
Why are leading zeros rejected?
Because different software reads them differently. In the classic BSD inet_aton behavior (still followed by some libraries and by ping on many systems), 010.0.0.1 is octal and means 8.0.0.1. Other parsers treat it as decimal 10. That ambiguity has caused real security bugs in allow-lists and SSRF filters, which is why modern parsers such as Python's ipaddress (since 3.9.5) reject leading zeros outright.
This pattern follows the strict rule: each octet is 0 or a number without a leading zero. If you must accept legacy input, normalize it explicitly instead of loosening the regex.
How do I check for private or reserved addresses?
A regex can do it, but a parser is clearer and tracks the official registry. In Python, ipaddress.ip_address(s).is_private; in Go, netip.ParseAddr(s) and addr.IsPrivate(); in Node.js, net.isIPv4(s) for the format plus a CIDR check.
| Range | Meaning |
|---|---|
10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 | Private networks (RFC 1918) |
127.0.0.0/8 | Loopback |
169.254.0.0/16 | Link-local (and cloud metadata at 169.254.169.254) |
0.0.0.0/8 | "This network" |
Blocking these ranges matters when your server fetches user-supplied URLs.
How do I use the IPv4 address regex in JavaScript, Python, Go, C# and PHP?
The pattern is translated for each engine rather than pasted as is: named groups, anchors, escapes, shorthand classes and flags are adjusted so each snippet behaves as closely to the JavaScript version as its engine allows. Differences that remain (Go's RE2 has no lookarounds or backreferences, for example) are called out under each one. The Code tab in the tester above also exports Dart, and updates as you edit the pattern.
JavaScript and TypeScript
const regex = /^(?:(?: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)$/;
function isValid(value) {
return regex.test(value);
}
console.log(isValid("192.168.1.1"));Python
import re
pattern = re.compile(r"^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\Z")
def is_valid(value: str) -> bool:
return pattern.search(value) is not None
print(is_valid("192.168.1.1"))- \d and \w are written as [0-9] and [A-Za-z0-9_] because in Python they also match digits and letters from other scripts.
- JavaScript's $ only matches at the very end of the string. Python's $ also matches before a trailing newline, so the pattern uses \Z instead.
Go
package main
import (
"fmt"
"regexp"
)
func main() {
re := regexp.MustCompile(`^(?:(?: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)$`)
fmt.Println(re.MatchString("192.168.1.1"))
}C#
using System;
using System.Text.RegularExpressions;
// The timeout stops a pathological input from hanging the thread (ReDoS).
var regex = new Regex(@"^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\z", RegexOptions.None, TimeSpan.FromSeconds(1));
Console.WriteLine(regex.IsMatch("192.168.1.1"));- \d and \w are written as [0-9] and [A-Za-z0-9_] because in .NET they also match digits and letters from other scripts.
- JavaScript's $ only matches at the very end of the string. .NET's $ also matches before a trailing newline, so the pattern uses \z instead.
PHP
<?php
$pattern = '/^(?:(?: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)$/D';
function isValid(string $value, string $pattern): bool
{
return preg_match($pattern, $value) === 1;
}
var_dump(isValid('192.168.1.1', $pattern));- The D modifier makes $ match only at the very end, like JavaScript (PCRE's $ also matches before a trailing newline).
Which related regex patterns are useful?
- Regex for IPv6 Addresses: Eight hextets, or fewer with a single :: compression, like 2001:db8::1.
- Regex for MAC Addresses: Six hex pairs with consistent : or - separators, or Cisco's dotted form.
- Regex for Domain Names: Hostnames with valid labels, a 253-character limit and Punycode support.
- Regex for URL Validation: http and https links with a real domain, optional port, path, query and fragment.
Browse all 25 patterns in the regex pattern library, or build your own in the regex tester.
Frequently asked questions
Last updated by the Playxoft engineering team.