本页面有中文版。
Cette page est disponible en français.
Esta página está disponible en español.
Patterns1 live hunt inside

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.

Regex Hunter logo

· 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.

Quick answerJavaScript
/^(\+?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:

Matches4/4 as expected
/^\d{3}-\d{3}-\d{4}$/

Should match1/1

  • 555-123-4567

Should not3/3

  • 555.123.4567
  • 555 123 4567
  • 555-1234
Try it in the Playground
Only the dashed form passes. The dotted and spaced versions are the same number, and they're rejected.

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.

Matches7/7 as expected
/^\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
Try it in the Playground
Dashes, dots, spaces or nothing at all. The digit counts still have to be exactly 3, 3 and 4.

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):

Matches4/4 as expected
/^\d{3}([-. ]?)\d{3}\1\d{4}$/

Should match2/2

  • 555-123-4567
  • 5551234567

Should not2/2

  • 555-123.4567
  • 555 123-4567
Try it in the Playground
([-. ]?) captures whatever separator was used, even an empty one, and \1 demands the same one again.

03Parentheses around the area code

The tempting fix for (555) 123-4567 is to make each parenthesis optional with \(? and \)?. That accepts unbalanced input:

Matches3/3 as expected
/^\(?\d{3}\)?[-. ]?\d{3}[-. ]?\d{4}$/
  • (555) 123-4567
  • (555-123-4567
  • 555) 123-4567
Try it in the Playground
Both parentheses are optional on their own, so a lone ( or ) gets through.

Alternation fixes it. Either the area code is in parentheses (with an optional space after), or it's bare (with an optional separator after):

Matches6/6 as expected
/^(\(\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
Try it in the Playground
Two branches for the area code. A ( without its ) matches neither branch.

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:

Matches7/7 as expected
/^(\+?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
Try it in the Playground
(\+?1[-. ]?)? is an optional plus, a 1 and an optional separator. The whole group can be skipped.

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:

Matches5/5 as expected
/^[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
Try it in the Playground
123-456-7890 is out because its area code starts with 1. The last two have exchanges starting with 0 and 1, and that includes the example we've used all along.

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.

Matches7/7 as expected
/^\+[1-9]\d{1,14}$/

Should match3/3

  • +15551234567
  • +442079460958
  • +8613800138000

Should not4/4

  • 5551234567
  • +1 555 123 4567
  • +0123456789
  • +1234567890123456
Try it in the Playground
A plus, a non-zero first digit, then up to 14 more digits. No spaces, dashes or parentheses.

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:

Pattern8 chars
/[\s().-]/
Try it in the Playground
Any space, parenthesis, dot or dash. Replace every match with nothing to turn "+1 (555) 123-4567" into "+15551234567".

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 (+999 isn'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:

Live huntpar 11

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.

Try it in the Playground
Like this? A new one drops every day.Play today’s hunt

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