libphonenumber - formatting phone numbers without knowing the country code
Asked Answered
G

2

19

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 !

Goring answered 26/9, 2018 at 14:23 Comment(2)
Found any solution for this?Groundsheet
@niroshan Sorry, no, and project is abandoned for now. But when I am using my Phone / Contact app on my Android device, somehow, it knows how to format the whole number (with spacing) even though there were no international indicator nor country code. My guess is that it may uses the Locale of the device to do so but I am not sure.Goring
T
3

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);
    }
}
Thrippence answered 26/9, 2018 at 14:30 Comment(3)
Thank you for the detailed answer, I really appreciate. All in all I understand your example, but there is one key point here where my real problem lies: the country code. In you example, it's Norway. But in my case, it can be anything ! That's really disturbing. I have my mobile phone (which serves as my data source for now) and I look at my contacts list. Some of them, it's numbers I know to be french, but without the +33, France's international code. How am I supposed to format these numbers into E164 ? I mean my SMS app seems to get it right... when I send / receive SMSGoring
Perhaps your SMS app asks the system which country it is in.Gilmore
this doesn't answer the question at all. If you pull the contact list to compare in a database you cannot ask the system which country it is in because you don't have access to each person phone the number refers to.Prewar
P
1

Store the original phone numbers in a non-operational column RAW_PHONE, and the canonical E.164 standardized number in you PHONE column ("00" -> "+", "(" -> "" and such). This way you are prepared for check lists and manual corrections, and improving the conversion.

Imaginable is having two phone columns in the table, and as second value just another extension -203.

Better not to fill the strict field if the conversion fails on country code or is otherwise dubious. Is the default France, or what when the user lives in Belgium? One might argue that the source (location) of user registration determines the default country code.

Playpen answered 26/9, 2018 at 14:51 Comment(2)
Thank you for your answer! This seems a good idea. As the user might sync my app with his contacts database on more than one occasion, I should handle when phone numbers are modified / added / deleted. My own concern so far, purely in terms of database, is how can I not insert a duplicate contact entry, because the phone number format changed, but basically it's the same number ? So, following your idea, I should come up with a constant format when storing numbers into RAW_PHONE so that I can make comparison. Do you think that'll work ? It all comes down to the comparison in the end.Goring
Another thing, though: how can I format the supplied phone number if it does not start with + ? AFAIK, the format method of the library requires a PhoneNumber to be formatted. And I can only get a PhoneNumber using the parse method, which in turns needs the country code if the number does not start with +. I believe your idea of a RAW_PHONE column should help there, but only if can strip down the number into raw digits only. Then comparison at this low level, when inserting, should work. Right ? How do you think I might achieve that ? Thanks for the help !Goring

© 2022 - 2024 — McMap. All rights reserved.