libphonenumber - formatting phone numbers without knowing the country code

Mackovich picture Mackovich · Sep 26, 2018 · Viewed 11.1k times · Source

I have heard a lot of good from what appears to be an awesome library but I find myself in a delicate situation.

This is the first project I have ever worked where I am supposed to store phone numbers in a database.

I have read a bit about the E.164 format and I do intend to store all phone numbers using this format in my database.

The problem I am facing, is the data source. I have no control over the data source. All I known is that I am receiving a bunch of phone numbers and their format is not consistent. Some have the international extension, some don't. Some have parenthesis, hyphens, leading 0, etc. some don't.

How could I possibly extract the phone numbers from said source, format them into E.164 so that I can store them safely ?

I have tried using the PhoneNumberUtil#parse() method without providing the country code, since I don't have access to that information.

Have a look at the following example:

System.out.printLn("Number -> " + phoneNumberUtil.parse("00336555233634", null).toString())

Error type: INVALID_COUNTRY_CODE. Missing or invalid default region.

In my example, the number is that of french mobile phone. The two starting 0 works if you dial from outside France, I believe.

But the library cannot understand it as it is laking the country code. Does that mean there does not exist a way to understand where that particular phone number is coming from ?

The documentation seems clear about it :

public PhoneNumber parse(CharSequence numberToParse, String defaultRegion)

@param defaultRegion region that we are expecting the number to be from. This is only used if * the number being parsed is not written in international format. The country_code for the *
number in this case would be stored as that of the default region supplied. If the number * is guaranteed to start with a '+' followed by the country calling code, then RegionCode.ZZ * or null can be supplied.

So, if add the +33

System.out.printLn("Number -> " + phoneNumberUtil.parse("+336555233634", null).toString())

Then naturally the result is:

Number -> Country Code: 33 National Number: 336555233634

What should / can I do if the end-user supplies my app with phone numbers that do not start with + ? I cannot believe I am the only one if this situation.

Thanks for the help !

Answer

VinuBibin picture VinuBibin · Sep 26, 2018

You need to use E164Format only. Here I took Norway as example

I have test case which tests and give the phone number in one format.

public static String getE164FormattedMobileNumber(String mobile, String locale)
            throws PhoneNumberFormatException {
        try {
            PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
            PhoneNumber phoneProto = phoneUtil.parse(mobile, locale);
            if (phoneUtil.isValidNumber(phoneProto)
                    && phoneUtil.isPossibleNumberForType(phoneProto, PhoneNumberType.MOBILE)) {
                return phoneUtil.format(phoneProto, PhoneNumberFormat.E164);
            }
            throw new PhoneNumberFormatException(
                    "Mobile number is invalid with the provided locale");
        } catch (NumberParseException e) {
            throw new PhoneNumberFormatException("Error in parsing mobile number", e);
        }
    }

and the test case as follows.

// this is the test mobile used
    private String expectedMobileNumber = "+4746205615";
private List<String> sucessMobileNumbers;

private List<String> failMobileNumbers;

public PhoneNumberE164FormatTest() {
    sucessMobileNumbers =
            Arrays.asList(
                    "46205615",
                    "004746205615",
                    "+4746205615",
                    "4746205615",
                    "46205615",
                    "+47 46205615",
                    "462 05 615");
    failMobileNumbers = Arrays.asList("abcdsds3434", "abcdsds343?#4", "21448410", "9946739087");
}

@Test
public void e164FormattedMobileNumbersSucessCase() throws PhoneNumberFormatException {

    for (String mobileNumber : sucessMobileNumbers) {
        Assert.assertEquals(
                expectedMobileNumber,
                (PhoneNumberUtils.getE164FormattedMobileNumber(mobileNumber, NO)));
    }
}

@Test(expected = PhoneNumberFormatException.class)
public void e164FormattedMobileNumbersFailCase() throws PhoneNumberFormatException {
    for (String mobileNumber : failMobileNumbers) {
        PhoneNumberUtils.getE164FormattedMobileNumber(mobileNumber, NO);
    }
}