Regex for phone numbers: US formats, E.164, and when to stop
People type the same phone number a dozen ways. Here's how to match US numbers with dashes, dots, spaces, parentheses and an optional +1, how to check the international E.164 format, and why real validation needs a library.

· 8 min read · Updated
/^\d{3}[-. ]?\d{3}[-. ]?\d{4}$/
match
- 555-123-4567
- 555.123.4567
- 5551234567
spare
- 555-1234
- 55-123-4567
- 555-123-456
Ask ten people for their phone number and you'll get it back in ten shapes: 555-123-4567, (555) 123-4567, 555.123.4567, +1 555 123 4567, 5551234567. They're all the same number.
A phone regex has to accept the shapes people actually type and still catch the obvious mistakes. This post builds a US pattern one piece at a time, then covers the international format, and ends with the part a regex can't do. Every example is live, so edit the patterns and watch the lines change.
/^ (\+? 1[-. ]?)? (\(\d{3}\) ?| \d{3}[-. ]?) \d{3}[-. ]?\d{4}$/A 10-digit US number with optional dashes, dots or spaces, brackets around the area code, and an optional +1 in front.
Accepts
- 555-123-4567
- (555) 123-4567
- +1 555.123.4567
Rejects
- 555-1234
- 55-123-4567
- 555-123-45678
01Start with the digits
A US number is a 3-digit area code, a 3-digit exchange and a 4-digit line number. The strictest version accepts exactly one format:
/^\d{3}-\d{3}-\d{4}$/Should match1/1
- 555-123-4567
Should not3/3
- 555.123.4567
- 555 123 4567
- 555-1234
That's fine if you control the input mask. If people type freely, it's too strict.
02Allow the common separators
Replace each dash with [-. ]?: a dash, a dot or a space, and the ? makes it optional so plain digits work too.
/^\d{3}[-. ]?\d{3}[-. ]?\d{4}$/Should match4/4
- 555-123-4567
- 555.123.4567
- 555 123 4567
- 5551234567
Should not3/3
- 555-1234
- 55-123-4567
- 555-123-456
One side effect: each separator is chosen on its own, so 555-123.4567 passes too. Usually that's harmless. If you want both separators to be the same, capture the first one and repeat it with a backreference (more on those in our backreferences guide):
/^\d{3}([-. ]?)\d{3}\1\d{4}$/Should match2/2
- 555-123-4567
- 5551234567
Should not2/2
- 555-123.4567
- 555 123-4567
03Parentheses around the area code
The tempting fix for (555) 123-4567 is to make each parenthesis optional with \(? and \)?. That accepts unbalanced input:
/^\(?\d{3}\)?[-. ]?\d{3}[-. ]?\d{4}$/- (555) 123-4567
- (555-123-4567
- 555) 123-4567
Alternation fixes it. Either the area code is in parentheses (with an optional space after), or it's bare (with an optional separator after):
/^(\(\d{3}\) ?|\d{3}[-. ]?)\d{3}[-. ]?\d{4}$/Should match4/4
- (555) 123-4567
- (555)123-4567
- 555-123-4567
- 555.123.4567
Should not2/2
- (555-123-4567
- 555) 123-4567
04The optional +1
The US country code is 1, written as +1, 1 or left off entirely. Wrap it in an optional group at the start:
/^(\+?1[-. ]?)?(\(\d{3}\) ?|\d{3}[-. ]?)\d{3}[-. ]?\d{4}$/Should match5/5
- +1 555 123 4567
- 1-555-123-4567
- +1 (555) 123-4567
- 15551234567
- 555-123-4567
Should not2/2
- +44 20 7946 0958
- 555-1234
That's a solid pattern for a US-only form.
05Tighten it with area code rules
Real US area codes and exchanges (the middle three digits) never start with 0 or 1. Swapping \d{3} for [2-9]\d{2} in those two spots rejects the classic fake number:
/^[2-9]\d{2}[-. ]?[2-9]\d{2}[-. ]?\d{4}$/Should match2/2
- 212-555-0199
- 415.555.2671
Should not3/3
- 123-456-7890
- 555-012-3456
- 555-123-4567
Whether that's worth it depends on your users. It catches a few typos, and it also makes the pattern harder to read.
06International numbers: E.164
Outside the US, formats vary too much for one pattern. Instead of trying, most systems store numbers in E.164, the international standard: a +, the country code, then the number, with no spaces or punctuation and at most 15 digits. Country codes never start with 0.
/^\+[1-9]\d{1,14}$/Should match3/3
- +15551234567
- +442079460958
- +8613800138000
Should not4/4
- 5551234567
- +1 555 123 4567
- +0123456789
- +1234567890123456
The usual approach is to let people type their number however they like, strip the punctuation, and then check the result. A regex is perfect for the stripping step:
/[\s().-]/In Python that's re.sub(r"[\s().-]", "", number). In JavaScript, number.replace(/[\s().-]/g, "").
07What a regex can't tell you
^\+[1-9]\d{1,14}$ checks the shape. It can't tell you:
- whether the country code exists (
+999isn't one, and the pattern accepts it), - whether the length is right for that country (UK numbers and German numbers have different lengths, and some countries mix lengths),
- whether the number is a mobile, a landline or unassigned,
- whether anyone answers.
For real validation, use libphonenumber, Google's phone number library. It knows the numbering plan of every country, and it has ports for most languages: phonenumbers in Python and libphonenumber-js in JavaScript. It also formats numbers for display and converts them to E.164 for storage:
import phonenumbers
n = phonenumbers.parse("(212) 555-0199", "US")
phonenumbers.format_number(n, phonenumbers.PhoneNumberFormat.E164) # '+12125550199'
phonenumbers.is_possible_number(n) # True: the length fits the US plan
And like with email addresses, the only way to prove a number works is to send a code to it.
08Try one
Here's a board of phone numbers in mixed formats. You don't need to check every format separately. Every monster has ten digits in a row (ignoring the punctuation), and no innocent does:
Catch the full US phone numbers, spare the short ones.
Targets · 0/5 caught
- 555-123-4567target
- (555) 123-4567target
- 555.123.4567target
- 5551234567target
- +1 555 123 4567target
Innocents · 0 hit
- 555-1234innocent
- 12345-6789innocent
- 2026-10-12innocent
- 555-123-456innocent
- 911innocent
Type a regex — the board updates as you go.
09Checklist
- For US-only input,
^(\+?1[-. ]?)?(\(\d{3}\) ?|\d{3}[-. ]?)\d{3}[-. ]?\d{4}$covers the common formats. - Use alternation, not two optional parentheses, so
(and)come as a pair. - For international numbers, strip punctuation with
[\s().-]and store E.164. - Check the shape with
^\+[1-9]\d{1,14}$, and use libphonenumber when it matters. - Send a code if you need to know the number is real.
10Keep practising
- The Real-world validators track in the Academy covers ZIP codes, dates, times, emails and more, one hunt at a time.
- The common patterns section of the guide has more live examples.
- Try today's hunt, or work through older boards in the archive.