Regex Patterns Library
Browse copy-paste regex patterns — pragmatic and strict variants, CI-verified match tables and six-language usage for each.
Identifiers
| Pragmatic | Verified vectors | |
|---|---|---|
| regex for email | /^[^\s@]+@[^\s@]+\.[^\s@]+$/ | 15 |
| regex for phone number | /^\+?[1-9]\d{1,14}$/ | 10 |
| uuid regex | /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i | 10 |
Network
| Pragmatic | Verified vectors | |
|---|---|---|
| ip address regex | /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/ | 12 |
| url regex | /^https?:\/\/[^\s/$.?#][^\s]*$/i | 13 |
| ipv6 regex | /^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$/i | 12 |
Formats
| Pragmatic | Verified vectors | |
|---|---|---|
| date regex yyyy-mm-dd | /^\d{4}-\d{2}-\d{2}$/ | 11 |
| regex for numbers only | /^\d+$/ | 12 |
| password regex | /^(?=.*[A-Za-z])(?=.*\d).{8,}$/ | 10 |
Do it offline:$ grep -E '^[0-9]{4}-[0-9]{2}-[0-9]{2}$' dates.txt
How to use it
- Pick a pattern from the browse tables above — the nine head intents are grouped into identifiers, network shapes and text formats, and every row shows its pragmatic source up front so you can judge the flavor at a glance.
- On the pattern page, switch between the pragmatic and strict variants, read what each one deliberately does not match, and find the rows of the verified vectors table closest to your own data.
- Copy the spelling for your language — JavaScript, Python, Java, Go, C# or PHP — or edit the preloaded pattern in the embedded tester and copy the line it just validated.
Nine copy-paste regular expressions — email, phone number, IPv4, URL, ISO date, digits-only, password policy, UUID and IPv6 — each on its own page in two honest variants: a pragmatic gate for what real data looks like, and a strict form that pins the detail a specification cares about. Every row of every match table is re-executed by the build before it is published, and each page preloads the live tester for immediate edits.
How it works
Each of the nine patterns lives in one data pack as two sources — pragmatic and strict — plus a table of input vectors, and every vector carries a human-authored expected mark. The pages, the tester preloads and the tests all read that same pack, so a correction lands everywhere at once or fails the build trying.
On every test run, each vector is executed against both variants through the same engine call the embedded tester uses, and the result must equal its authored mark exactly. Before a mark is ever committed, an independent generator re-proves it twice — once with the platform's bare RegExp, once through Python 3 against the frozen re.compile spelling — which is precisely what the machine-verified badge on the JavaScript and Python blocks means.
The Java, Go, C# and PHP spellings are produced by pure escaping rules and carry a syntax-reviewed badge instead — reviewed, not machine-verified, and the badge never claims more. Where an engine genuinely differs, the page says so in a compatibility note: Go's RE2 refuses lookaheads, and Python's str-pattern \d reaches beyond ASCII.
Examples
^[^\s@]+@[^\s@]+\.[^\s@]+$pattern /^[^\s@]+@[^\s@]+\.[^\s@]+$/
a@b.co ✓ matches
a@b ✗ no match
a b@c.d ✗ no match
jane.doe+archive@mail.example.com ✓ matchesThe spec's own acceptance rows: one @, no spaces, a dot somewhere in the domain. This gate stops the two classic paste accidents — a dotless domain and an inner space — while keeping plus-tagged addresses that folklore patterns turn away.
^\d{4}-\d{2}-\d{2}$pragmatic /^\d{4}-\d{2}-\d{2}$/
strict /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$/
2026-08-06 pragmatic ✓ matches strict ✓ matches
2026-13-01 pragmatic ✓ matches strict ✗ no match
2026-02-31 pragmatic ✓ matches strict ✓ matchesThe divergent middle row is the whole lesson: month 13 slips through the shape-only gate and stops at the strict range check. The last row shows the honest limit — February 31st satisfies both variants, because only a date parser knows the calendar.
^(?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$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
2001:db8::8a2e:370:7334 pragmatic ✗ no match strict ✓ matches
::1 pragmatic ✗ no match strict ✓ matches
2001:db8::1::2 pragmatic ✗ no match strict ✗ no matchIPv6 inverts the usual relationship: strict accepts more here, because pragmatic pins the full eight-group form while strict adds the :: compression grammar. Double compression fails both variants — RFC 5952 allows :: at most once per address.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
Pragmatic first, strict when ambiguity costs you
The two variants disagree on purpose. Pragmatic gates the shape real data arrives in and tolerates oddities such as zero-padded octets; strict refuses whatever a downstream parser could read two ways. Start pragmatic at input boundaries, and reach for strict when the value feeds systems that must agree with each other — the divergent rows in each vectors table show exactly what switching buys and breaks.
Anchored validators do not extract
Every source in this library starts with ^ and ends with $, so it validates one whole field and finds nothing inside larger text. To extract instead, drop the anchors and add the g flag in the tester — then expect more false positives, because the surrounding context no longer does the filtering the anchors did.
grep -E speaks POSIX ERE, not JavaScript
The command line above runs the date check as an ERE: [0-9] classes stand in for \d, which BSD grep does not understand, and lookaheads do not exist there at all — the password policy has no single-grep port. Translate the shorthand classes before shelling out, or pipe through node when a pattern leans on JavaScript-only syntax.
Common errors
Invalid regular expression: /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?/: Unterminated group- Raised when a copied pattern loses its tail — this one is the library's own IPv4 row missing its final two characters, so every opened group counts but one never closes. Re-copy the whole line from the pattern page; the wording after the second slash comes from Node's V8, and your browser may phrase the same refusal differently.
Invalid regular expression: /(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/: Invalid group- The (?P<name>…) spelling is Python's; JavaScript names groups (?<name>…) with no P, so the port dies at the first parenthesis. Drop each P and the same groups compile — the Python usage block on every pattern page performs that translation in the opposite direction.
FAQ
Which regex flavor are these patterns written for?
JavaScript — the source of truth is what new RegExp compiles, exercised in Node's V8 by the test suite and in your own browser by the embedded tester. The six usage blocks re-spell each pattern idiomatically per language, and a compatibility note appears wherever behavior genuinely diverges instead of a silent copy-paste trap.
When should I choose the strict variant over the pragmatic one?
Choose strict when two systems must read the value identically — canonical IPv4 refuses zero-padded octets exactly because inet_aton-style parsers take 0177 for octal. For a signup form, pragmatic plus a downstream check is usually kinder: obvious garbage still bounces, while unusual-but-valid data gets through.
How are the match tables verified, exactly?
Each row's expected result is authored by hand, then proven twice: an independent script re-executes it with the bare RegExp built into the platform and through Python 3 at generation time, and the test suite re-runs every row through the live engine on every build. A row that stops agreeing with its mark fails CI, so the tables cannot rot silently.
Why is there no fully RFC-compliant email pattern here?
Because the grammar RFC 5322 allows — nested comments, quoted local parts, address literals — fits one regex badly, and the popular attempts pay for their coverage with catastrophic backtracking. The email page prints one such classic strictly as a warning, never runs it, and gates addresses pragmatically: check the shape, then prove the mailbox by sending to it.
Can I paste these into Python, Java, Go, C# or PHP unchanged?
Paste the language block, not the JavaScript literal — delimiters and escaping differ per host, and each block is already spelled for its language. Two real limits are documented where they bite: Go's RE2 refuses the password policy's lookaheads outright, and Python's str-pattern \d admits non-ASCII digits unless re.ASCII is passed.
What if none of the nine patterns fits my case?
Open the nearest page and bend its pattern in the embedded tester: pattern, flags and a sample string arrive preloaded, edits re-run as you type, and the share link hands your exact state to the full tester. The vectors table doubles as a checklist — feed the tester your own inputs and watch which variant agrees with you.