The standard regex for an international phone number is ^\+[1-9]\d{1,14}$, which accepts a plus sign, a country code that does not start with zero, and at most 15 digits in total. This is the E.164 format that phone carriers, SMS gateways and most APIs expect. A regex checks this shape, but it cannot know whether a country code exists or whether a number has the right length for its country.
We use the E.164 regex to check API fields and stored numbers, the spaced E.123 variant for numbers that people type, and Google’s libphonenumber library when we need to know that a number is real.
The following example checks a London number in three notations with the patterns and helper methods from this article. The sample numbers come from ranges reserved for fiction, 020 7946 0xxx in the UK and 555-01xx in North America.
Pattern e164 = Pattern.compile("^\\+[1-9]\\d{1,14}$");
boolean compact = e164.matcher("+442079460958").matches(); // true
boolean spaced = e164.matcher("+44 20 7946 0958").matches(); // false, spaces
boolean e123 = PhoneFormats.E123.matcher("+44 20 7946 0958").matches(); // true
Optional<String> stored = PhoneFormats.toE164("+44 (20) 7946-0958"); // Optional[+442079460958]
boolean real = PhoneCheck.isValid("+44 20 7946 0958"); // true (libphonenumber)
boolean tooShort = PhoneCheck.isValid("+44 20 7946 095"); // false, one digit short
Notice that the strict E.164 regex rejects spaces, so we either accept the E.123 notation or remove the separators before the check. We start with the E.164 rules, write a regex for each notation, normalize user input, cover the EPP format used by domain registries, and finish with full validation in libphonenumber. The regex basics are in our guide to regular expressions in Java.
1. The E.164 Format in Short
ITU-T Recommendation E.164 is the international numbering plan. It defines a number as a country code of 1 to 3 digits followed by the national number. The whole number has at most 15 digits, not counting the plus sign. No country code starts with 0.
Written in E.164 form, a number has no spaces, dashes or parentheses.
- The number “+442079460958” is a London number with country code 44 and national number 2079460958.
- The number “+12025550123” is a North American number with country code 1 and national number 2025550123.

Because the format is fixed, E.164 is the best form for storing numbers in a database and sending them to an SMS or voice API. The three notations differ only in the separators they allow, so each one gets its own short regex.
| Format | Example | Regex |
|---|---|---|
| E.164 | +442079460958 | ^\+[1-9]\d{1,14}$ |
| E.123 international | +44 20 7946 0958 | ^\+[1-9](?: ?\d){6,14}$ |
| EPP (RFC 5733) | +44.2079460958 | ^\+[1-9]\d{0,2}\.\d{4,14}$ |
2. Regex for E.164 Numbers
The E.164 regex follows the definition one part at a time.
| Part | Meaning |
|---|---|
| ^ | Start of the input |
| \+ | A literal plus sign; the backslash is needed because + is a quantifier |
| [1-9] | The first digit of the country code, never 0 |
| \d{1,14} | 1 to 14 more digits, for 15 digits at most |
| $ | End of the input |
In a Java string literal, every backslash is doubled. We compile the pattern once and reuse it, because compiling a regex on every call costs time.
Pattern e164 = Pattern.compile("^\\+[1-9]\\d{1,14}$");
boolean london = e164.matcher("+442079460958").matches(); // true
boolean washington = e164.matcher("+12025550123").matches(); // true
boolean sydney = e164.matcher("+61255501234").matches(); // true
boolean tooLong = e164.matcher("+1234567890123456").matches(); // false, 16 digits
boolean zero = e164.matcher("+0442079460958").matches(); // false, starts with 0
boolean noPlus = e164.matcher("442079460958").matches(); // false, no plus sign
boolean dashes = e164.matcher("+44-20-7946-0958").matches(); // false, dashes
boolean tiny = e164.matcher("+12").matches(); // true
The last line shows the weak spot of \d{1,14}. The standard sets a maximum, not a useful minimum, so “+12” passes. If our users are people with ordinary phone numbers, raising the lower bound to \d{6,14} (7 digits at least) removes obvious junk without rejecting real numbers.
3. Allowing Spaces With the E.123 Notation
People rarely type a number as one block of digits. ITU-T E.123 describes how to print numbers for humans, with a leading plus sign and groups of digits separated by spaces, for example “+44 20 7946 0958”. The following regex accepts a single optional space before each digit after the first one.
Pattern e123 = Pattern.compile("^\\+[1-9](?: ?\\d){6,14}$");
boolean london = e123.matcher("+44 20 7946 0958").matches(); // true
boolean washington = e123.matcher("+1 202 555 0123").matches(); // true
boolean compact = e123.matcher("+442079460958").matches(); // true
boolean twoSpaces = e123.matcher("+44 20 7946 0958").matches(); // false, two spaces
boolean trailing = e123.matcher("+44 20 7946 0958 ").matches(); // false, trailing space
boolean dashes = e123.matcher("+44-20-7946-0958").matches(); // false, dashes
The group (?: ?\d) is a non-capturing group, which groups items without storing the match. Each repetition is “an optional space followed by a digit”, so a space can never come first, last or twice in a row. Counting the group repetitions counts digits, not characters, which is why {6,14} still means 7 to 15 digits in total.
4. Normalizing Input to E.164
Say a food delivery app sends an SMS when the rider is close. Customers type their numbers as “+44 (20) 7946-0958”, “+1.202.555.0123” or “0044 20 7946 0958”, but the SMS API accepts only E.164. Instead of a regex that accepts every style, we remove the separators first and check the result with the strict E.164 regex, which keeps the regex short and gives a value that is ready to store.
final class PhoneFormats {
static final Pattern E164 = Pattern.compile("^\\+[1-9]\\d{1,14}$");
static final Pattern E123 = Pattern.compile("^\\+[1-9](?: ?\\d){6,14}$");
static final Pattern SEPARATORS = Pattern.compile("[\\s().-]");
static Optional<String> toE164(String input) {
if (input == null) {
return Optional.empty();
}
String digits = SEPARATORS.matcher(input).replaceAll("");
if (digits.startsWith("00")) {
digits = "+" + digits.substring(2);
}
return E164.matcher(digits).matches() ? Optional.of(digits) : Optional.empty();
}
}
The class [\s().-] matches whitespace, parentheses, dots and hyphens. Inside square brackets, the dot is a literal dot, and a hyphen at the end is a literal hyphen. The 00 rule converts the international call prefix used in Europe and many other regions into a plus sign.
Optional<String> uk = PhoneFormats.toE164("+44 (20) 7946-0958"); // Optional[+442079460958]
Optional<String> dots = PhoneFormats.toE164("+1.202.555.0123"); // Optional[+12025550123]
Optional<String> us = PhoneFormats.toE164("+1 (202) 555-0123"); // Optional[+12025550123]
Optional<String> prefix = PhoneFormats.toE164("0044 20 7946 0958"); // Optional[+442079460958]
Optional<String> ext = PhoneFormats.toE164("+44 20 7946 0958 ext 12"); // Optional.empty
The method toE164() needs the country code in the input. A national number such as “020 7946 0958” has no country code, and no regex can guess it. As we will see in section 6, libphonenumber handles that case with a default region.
5. The EPP Phone Format
The Extensible Provisioning Protocol (EPP) is used between domain registries and registrars, and its contact mapping in RFC 5733 section 2.5 defines its own phone format. The number starts with a plus sign and the country code, followed by a dot and the number, as in “+44.2079460958”. In the EPP XML, an extension is a separate x attribute, and many applications that store the format as text append it as “x123”.
The dot separates the country code from the rest, so named groups can read each part back. A named group, written (?<name>…), captures its part of the match under a name, which reads better than group(1).
Pattern epp = Pattern.compile("^\\+(?<cc>[1-9]\\d{0,2})\\.(?<number>\\d{4,14})(?:x(?<ext>\\d{1,6}))?$");
Matcher m = epp.matcher("+44.2079460958x123");
boolean found = m.matches(); // true
String cc = m.group("cc"); // "44"
String number = m.group("number"); // "2079460958"
String ext = m.group("ext"); // "123"
boolean plain = epp.matcher("+1.2025550123").matches(); // true
boolean spaced = epp.matcher("+1 202 555 0123").matches(); // false
boolean longCc = epp.matcher("+1234.2025550123").matches(); // false, 4-digit country code
The extension group is optional because of the ? after it, so “+1.2025550123” matches and group(“ext”) returns null for it.
6. Full Validation With libphonenumber
A regex does not know the numbering plan of each country. The next two inputs have a valid E.164 shape, but neither is a real number.
Pattern e164 = Pattern.compile("^\\+[1-9]\\d{1,14}$");
boolean shape999 = e164.matcher("+999123456789").matches(); // true
boolean real999 = PhoneCheck.isValid("+999123456789"); // false, unassigned country code
boolean shapeUk = e164.matcher("+4420794609").matches(); // true
boolean realUk = PhoneCheck.isValid("+4420794609"); // false, too short for the UK
libphonenumber is Google’s open-source library for parsing, formatting and validating phone numbers, and Android uses it. It contains the numbering plan of every country, including valid lengths and number ranges. For production code, we parse with libphonenumber and store the E.164 output, and the regex stays useful as a quick check in the browser or in a log filter.
<dependency>
<groupId>com.googlecode.libphonenumber</groupId>
<artifactId>libphonenumber</artifactId>
<version>9.0.41</version>
</dependency>
Version 9.0.41 is the latest on Maven Central in October 2026. The library publishes new versions often, because numbering plans keep changing, so we check for a newer one before adding it.
The entry point is PhoneNumberUtil. Its parse() method takes the text and a default region. With null as the region, the text must start with a plus sign.
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
PhoneNumber n = util.parse("+44 20 7946 0958", null);
int countryCode = n.getCountryCode(); // 44
long national = n.getNationalNumber(); // 2079460958
boolean valid = util.isValidNumber(n); // true
String region = util.getRegionCodeForNumber(n); // "GB"
PhoneNumberUtil.PhoneNumberType type = util.getNumberType(n); // FIXED_LINE
String e164 = util.format(n, PhoneNumberFormat.E164); // "+442079460958"
String international = util.format(n, PhoneNumberFormat.INTERNATIONAL); // "+44 20 7946 0958"
String nationalText = util.format(n, PhoneNumberFormat.NATIONAL); // "020 7946 0958"
PhoneNumber us = util.parse("(202) 555-0123", "US");
String usE164 = util.format(us, PhoneNumberFormat.E164); // "+12025550123"
The default region solves the problem from section 4. The text “(202) 555-0123” has no country code, and the region “US” supplies it. Text that is not a phone number makes parse() throw the checked exception NumberParseException, so the helper isValid() used in the first example catches it and returns false.
final class PhoneCheck {
private static final PhoneNumberUtil UTIL = PhoneNumberUtil.getInstance();
static boolean isValid(String input) {
if (input == null) {
return false;
}
try {
return UTIL.isValidNumber(UTIL.parse(input, null));
} catch (NumberParseException e) {
return false; // NOT_A_NUMBER, INVALID_COUNTRY_CODE, TOO_SHORT_NSN, ...
}
}
}
boolean word = PhoneCheck.isValid("hello"); // false, NOT_A_NUMBER
boolean noCountry = PhoneCheck.isValid("020 7946 0958"); // false, no country code and no region
7. Which Check to Use
The right tool depends on where the number comes from and what we do with it.
- For an API field that must already be in E.164, the regex ^\+[1-9]\d{1,14}$ is enough.
- For a form where users type numbers freely, we strip separators and check E.164, or, better, parse with libphonenumber and a default region taken from the user’s country.
- For stored numbers that we call or text, we validate with libphonenumber and store the E.164 string.
- To know that a number belongs to the user, we send a one-time code by SMS, because no format check can prove ownership.
The example project contains the three regexes, both helper classes and the libphonenumber calls, with JUnit tests for each result.
8. International Phone Number Regex FAQs
Teams that store phone numbers for SMS or calls run into these questions.
8.1. What Is the Maximum Length of an International Phone Number?
15 digits, without the plus sign. E.164 limits the country code and the national number together to 15 digits, so \d{1,14} after the first digit enforces that limit.
8.2. Is the Plus Sign Required in E.164?
Yes, in the written E.164 form that APIs expect. Some systems store the digits without the plus sign, but a stored “12025550123” looks like a national number, so we keep the plus sign.
8.3. Can a Regex Validate the Country Code?
Only partly. A regex can list the country codes we accept, for example ^\+(?:1|44|61)\d{6,14}$, but the valid national lengths differ per country and change over time. libphonenumber keeps that data current.
8.4. How Do We Convert a Local Number to E.164 in Java?
We parse it with libphonenumber and a default region, and format the result with PhoneNumberFormat.E164.
PhoneNumberUtil util = PhoneNumberUtil.getInstance();
String london = util.format(util.parse("020 7946 0958", "GB"), PhoneNumberFormat.E164); // "+442079460958"
8.5. Does the Regex Accept Numbers With an Extension?
No, E.164 has no extension. We store the extension in a separate field, or use the EPP format from section 5 with its optional x part.
9. Conclusion
The regex ^\+[1-9]\d{1,14}$ checks the E.164 shape, which is a plus sign, no leading zero and at most 15 digits. Spaced input fits the E.123 regex, or we strip separators and check E.164.
Because a regex knows nothing about real country codes and number lengths, production code parses numbers with libphonenumber and stores the E.164 result.
10. References
- ITU-T E.164, The international public telecommunication numbering plan
- ITU-T E.123, Notation for national and international telephone numbers
- RFC 5733, EPP Contact Mapping, section 2.5
- libphonenumber on GitHub
- Pattern (Java SE 25 API)
Happy Learning !!
Hi,
How to validate the phone number with country code and exactly 10 digits.
would it be “^\\+(?:[0-9] ?){10}[0-9]$”
the above one doesn’t work for me
can someone help me out
eg +91 9876543213
the “9876543213” part should be exactly 10 digits