Blog ·
Regex Phone Number Patterns for Common Formats
Use this regex to match common US and Canadian phone formats like (555) 123-4567 and +1 555.123.4567, plus extraction, E.164 and pitfalls.
Regex Tester
Test JavaScript regular expressions with match highlighting and capture groups.
A single regex can match the common written forms of North American (NANP) phone numbers, including an optional +1 country code. Here is the pattern:
^(?:\+?1[-.\s]?)?(?:\(\d{3}\)|\d{3})[-.\s]?\d{3}[-.\s]?\d{4}$It checks the shape of the number, not whether the number is assigned or in service. For numbers outside the US and Canada, normalize to E.164 and use a library instead (see below). You can paste the pattern into the Regex Tester along with a list of sample numbers to see which lines match before you put it in code. The tester uses JavaScript regex syntax, so test the JavaScript version of the pattern there.
Common US formats and what they match
Against the pattern above:
555-123-4567matches(555) 123-4567matches555.123.4567matches555 123 4567matches5551234567matches1-555-123-4567matches+1 555 123 4567matches555-1234does not match (no area code)555-123-456does not match (too short)0555 123 4567does not match (the leading 0 makes the area code and exchange fail to line up)(555-123-4567does not match (unbalanced parenthesis)
Breaking down the pattern
^and$anchor the match to the whole string, so extra characters cause a failure.(?:\+?1[-.\s]?)?is an optional country code: an optional plus sign, the digit 1, and an optional separator. The group is non-capturing, so match results don't include extra groups.(?:\(\d{3}\)|\d{3})is the area code, either in parentheses or bare. The two alternatives keep unbalanced input like(555out.[-.\s]?\d{3}[-.\s]?\d{4}is the exchange and line number, each optionally preceded by a dash, dot or whitespace.
Validating a number in code
In JavaScript, use a regex literal with the anchors:
const US_PHONE = /^(?:\+?1[-.\s]?)?(?:\(\d{3}\)|\d{3})[-.\s]?\d{3}[-.\s]?\d{4}$/;
US_PHONE.test('(555) 123-4567'); // true
US_PHONE.test('+1 555 123 4567'); // true
US_PHONE.test('555-1234'); // falseIn Python, drop the anchors and use fullmatch on the stripped input:
import re
US_PHONE = re.compile(r'(?:\+?1[-.\s]?)?(?:\(\d{3}\)|\d{3})[-.\s]?\d{3}[-.\s]?\d{4}')
print(bool(US_PHONE.fullmatch('+1 555 123 4567'.strip()))) # True
print(bool(US_PHONE.fullmatch('555-1234'))) # FalseExtracting phone numbers from text
To find numbers inside a longer string, the anchors won't work. Use lookarounds so you don't match ten digits in the middle of a longer number, such as an order ID.
const re = /(?<!\d)(?:\+?1[-.\s]?)?(?:\(\d{3}\)|\d{3})[-.\s]?\d{3}[-.\s]?\d{4}(?!\d)/g;
const text = 'Call (555) 123-4567 or +1 555.987.6543 today.';
console.log(text.match(re));
// [ '(555) 123-4567', '+1 555.987.6543' ]import re
pattern = re.compile(r'(?<!\d)(?:\+?1[-.\s]?)?(?:\(\d{3}\)|\d{3})[-.\s]?\d{3}[-.\s]?\d{4}(?!\d)')
print(pattern.findall('Call (555) 123-4567 or +1 555.987.6543 today.'))
# ['(555) 123-4567', '+1 555.987.6543']Pitfalls that show up in real code
- Missing anchors. Without
^and$(or fullmatch in Python), the pattern succeeds on any string that contains ten digits somewhere, such asorder 12345678901234. - Trailing newlines in Python. In a pattern that ends with
$,re.matchtreats$as matching before a final newline, so'555-123-4567\n'passes. Usefullmatch, or end the pattern with\Z, and strip input first. In JavaScript,$without themflag only matches at the very end of the string. - Unicode digits in Python.
\dmatches any Unicode decimal digit, such as Arabic-Indic digits. Use[0-9]or there.ASCIIflag if you only want ASCII. - Non-breaking spaces. Text copied from web pages often contains U+00A0, which
\smatches. That's usually what you want, but it can surprise you when you compare strings. - Separators that are too narrow. A pattern that only allows dashes misses the dot and space formats that people commonly type.
- Structure is not validity. NANP rules require the first digit of the area code and the exchange to be 2 through 9. The pattern above doesn't enforce that, so
555-000-0000passes. Add[2-9]to those positions if you need that rule.
Validate by digits first
Many forms are easier to handle if you strip everything except digits, then check the length. This also handles inputs that mix styles.
const digits = input.replace(/\D/g, '');
const isUs = /^1?\d{10}$/.test(digits);This accepts 1234567890, which is not a valid NANP number, so add the area code rule if you need it. Extensions such as ext. 89 will fail this check, so handle them separately before stripping.
International numbers and E.164
E.164 is the international format: a plus sign, a country code, and the subscriber number, with no separators. It is at most 15 digits in total, and the first digit after the plus sign is never 0. A simple shape check is:
const E164 = /^\+[1-9]\d{1,14}$/;
E164.test('+442071838750'); // true (shape only)
E164.test('+0123'); // falseThis checks length and shape only. It doesn't confirm that the country code exists or that the number is in service. For forms that accept numbers from many countries, use a library built on country numbering plans, such as Google's libphonenumber or a port of it for your language. Store numbers in E.164 for matching and deduplication, and format them for display separately.
To normalize user input before storing, remove common separators, then check the result:
const normalized = input.replace(/[\s().-]/g, '');
This doesn't add a country code, so you still need to know which country the number belongs to.
What regex can't tell you
Regex can check that a string looks like a phone number. It can't tell you that the number belongs to the person who entered it. The same limits apply to email. See Regex for Email Validation for a longer discussion. If the number matters for sign-up or account recovery, send a verification code.
FAQ
Should I use a regex or a library for phone validation?
For one country with a fixed format, a regex is usually enough. For international forms, use a library that knows numbering plans, since lengths and prefixes differ by country.
Why does my pattern match numbers inside longer strings?
You're missing anchors, or you're using a search function where you need a full match. Use ^ and $ in JavaScript, fullmatch in Python, or lookarounds like (?<!\d) and (?!\d) when extracting from text.
Can one regex match phone numbers from every country?
Not practically. Lengths, prefixes, trunk digits and separators vary by country. A shape check against E.164 plus a library for country-specific rules is a more reliable approach.
Should I strip spaces and dashes before saving a phone number?
Yes, if you need matching or deduplication. Store a normalized form such as +15551234567 and keep the formatted version separately for display.
Regex Tester
Test JavaScript regular expressions with match highlighting and capture groups.