The standard regex for an international phone number is ^\+[1-9]\d{1,14}$: 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 can check this shape, but it cannot know whether a country code exists or whether a number has the right length for its country.
In this tutorial, we write regexes for the E.164 format, for the spaced E.123 notation and for the EPP format used by domain registries, and we normalize user input such as “+44 (20) 7946-0958” into E.164 before checking it. For full validation, we use Google’s libphonenumber library and compare its answers with the regex.
The sample numbers come from ranges reserved for fiction: 020 7946 0xxx in the UK and 555-01xx in North America.
| 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}$ |
In Java code, each check is one line once the patterns are compiled into constants:
E164.matcher("+442079460958").matches(); // true
E164.matcher("+44 20 7946 0958").matches(); // false, spaces
E123.matcher("+44 20 7946 0958").matches(); // true
toE164("+44 (20) 7946-0958"); // "+442079460958"
EPP.matcher("+44.2079460958x123").matches(); // true
isValid("+44 20 7946 0958"); // true (libphonenumber)
isValid("+44 20 7946 095"); // false, one digit short
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:
- “+442079460958” is a London number: country code 44, national number 2079460958.
- “+12025550123” is a North American number: country code 1, 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.
2. Regex for E.164 Numbers
The E.164 regex follows the definition directly:
| 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}$");
E164.matcher("+442079460958").matches(); // true
E164.matcher("+12025550123").matches(); // true
E164.matcher("+61255501234").matches(); // true
E164.matcher("+1234567890123456").matches(); // false, 16 digits
E164.matcher("+0442079460958").matches(); // false, starts with 0
E164.matcher("442079460958").matches(); // false, no plus sign
E164.matcher("+44-20-7946-0958").matches(); // false, dashes
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: 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: a leading plus sign and groups of digits separated by spaces, for example “+44 20 7946 0958”.
This regex accepts a single optional space before each digit after the first one:
Pattern E123 = Pattern.compile("^\\+[1-9](?: ?\\d){6,14}$");
E123.matcher("+44 20 7946 0958").matches(); // true
E123.matcher("+1 202 555 0123").matches(); // true
E123.matcher("+442079460958").matches(); // true
E123.matcher("+44 20 7946 0958").matches(); // false, two spaces
E123.matcher("+44 20 7946 0958 ").matches(); // false, trailing space
E123.matcher("+44-20-7946-0958").matches(); // false, dashes
The group (?: ?\d) is a non-capturing group: (?:…) groups items without storing the match. Each repetition is “an optional space, then 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
Forms receive numbers in many shapes: “+44 (20) 7946-0958”, “+1.202.555.0123”, “0044 20 7946 0958”. Instead of writing a regex that accepts every style, we remove the separators first and then apply the strict E.164 regex. This keeps the regex short, and the result is ready to store.
Pattern SEPARATORS = Pattern.compile("[\\s().-]");
String digits = SEPARATORS.matcher(input).replaceAll("");
if (digits.startsWith("00")) {
digits = "+" + digits.substring(2);
}
return E164.matcher(digits).matches() ? digits : null;
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.
toE164("+44 (20) 7946-0958"); // "+442079460958"
toE164("+1.202.555.0123"); // "+12025550123"
toE164("+1 (202) 555-0123"); // "+12025550123"
toE164("0044 20 7946 0958"); // "+442079460958"
toE164("+44 20 7946 0958 ext 12"); // null
This method 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. Section 6 shows how 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: a plus sign, the country code, a dot, and the number, as in “+44.2079460958”. In the EPP XML, an extension is a separate x attribute; 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:
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");
m.matches(); // true
m.group("cc"); // "44"
m.group("number"); // "2079460958"
m.group("ext"); // "123"
EPP.matcher("+1.2025550123").matches(); // true
EPP.matcher("+1 202 555 0123").matches(); // false
EPP.matcher("+1234.2025550123").matches(); // false, 4-digit country code
A named group, written (?<name>…), captures its part of the match under a name, which reads better than group(1). The extension group is optional thanks to the ? after 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:
E164.matcher("+999123456789").matches(); // true
isValid("+999123456789"); // false, unassigned country code
E164.matcher("+4420794609").matches(); // true
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; 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.40</version>
</dependency>
Version 9.0.40 was the latest on Maven Central when this was written. 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);
n.getCountryCode(); // 44
n.getNationalNumber(); // 2079460958
util.isValidNumber(n); // true
util.getRegionCodeForNumber(n); // "GB"
util.getNumberType(n); // FIXED_LINE
util.format(n, PhoneNumberFormat.E164); // "+442079460958"
util.format(n, PhoneNumberFormat.INTERNATIONAL); // "+44 20 7946 0958"
util.format(n, PhoneNumberFormat.NATIONAL); // "020 7946 0958"
PhoneNumber us = util.parse("(202) 555-0123", "US");
util.format(us, PhoneNumberFormat.E164); // "+12025550123"
The default region solves the problem from section 4: “(202) 555-0123” has no country code, and the region “US” supplies it. Text that is not a phone number throws a checked NumberParseException:
parse("hello", null) -> NOT_A_NUMBER: The string supplied did not seem to be a phone number.
The isValid() helper used in the quick reference wraps parse() and isValidNumber() and returns false when parsing throws.
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.
- For knowing that a number belongs to the user, we send a one-time code by SMS; no format check can prove that.
8. Building and Testing the E.164 Example
The project on GitHub has the three regexes, the toE164() and isValid() helpers, and the libphonenumber calls from this article. Its JUnit 6 tests assert every result shown above. It uses Java 25, Maven and libphonenumber 9.0.40.
mvn -q compile exec:java
mvn test
9. Conclusion
The regex ^\+[1-9]\d{1,14}$ checks the E.164 shape: 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
The ITU recommendations define the number format and the printed notation; RFC 5733 defines the EPP format.
- 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
- libphonenumber API (javadoc.io)
- 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