views:

4558

answers:

8

What is the best way for converting phone numbers into international format (E.164) using Java?

Given a 'phone number' and a country id (let's say an ISO country code), I would like to convert it into a standard E.164 international format phone number.

I am sure I can do it by hand quite easily - but I would not be sure it would work correctly in all situations.

Which Java framework/library/utility would you recommend to accomplish this?

P.S. The 'phone number' could be anything identifiable by the general public - such as

* (510) 786-0404
* 1-800-GOT-MILK
* +44-(0)800-7310658

that last one is my favourite - it is how some people write their number in the UK and means that you should either use the +44 or you should use the 0.

The E.164 format number should be all numeric, and use the full international country code (e.g.+44)

A: 

Here's a method that I've written that will format phone numbers to (###) ###-####:

String formatTeleNumber(String s) {
    StringBuffer number = new StringBuffer();

    if (s.length() == 0) {

        return "(999)999-9999";
    }

    // Strip all non-numbers
    for (int i = 0; i < s.length(); i++) {

        if (Character.isDigit(s.charAt(i))) {
           number.append(s.charAt(i));
        }
    }

    // Pad with 0s
    for (int i = number.length(); i < 10; i++) {

        number.insert(0, '0');
    }

    // Format telephone number to (###)###-####
    number = new StringBuffer(number.substring(number.length() - 10));
    number.insert(0, '(');
    number.insert(4, ')');
    number.insert(8, '-');

    return number.toString();
}

Simply strip out anything that's not a number, pad it with 0's (if required), and then insert the correct characters at the correct locations.

Joel
A: 

This is a very difficult task as phone numbers are written differently nearly in each country.

We used to keep a list of REGEXPs (we supported 19 formats) to parse 3 parts of a number and then converted those 3 parts to "+{1} {2} {3}".

Sort regexps by more specific first and then take the first which succeeds in parsing.

Vilmantas Baranauskas
+3  A: 

Speaking from experience at writing this kind of thing, it's really difficult to do with 100% reliability. I've written some Java code to do this that is reasonably good at processing the data we have but won't be applicable in every country. Questions you need to ask are:

Are the character to number mappings consistent between countries? The US uses a lot of this (eg 1800-GOT-MILK) but in Australia, as one example, its pretty rare. What you'd need to do is ensure that you were doing the correct mapping for the country in question if it varies (it might not). I don't know what countries that use different alphabets (eg Cyrilic in Russia and the former Eastern block countries) do;

You have to accept that your solution will not be 100% and you should not expect it to be. You need to take a "best guess" approach. For example, theres no real way of knowing that 132345 is a valid phone number in Australia, as is 1300 123 456 but that these are the only two patterns that are for 13xx numbers and they're not callable from overseas;

You also have to ask if you want to validate regions (area codes). I believe the US uses a system where the second digit of the area code is a 1 or a 0. This may have once been the case but I'm not sure if it still applies. Whatever the case, many other countries will have other rules. In Australia, the valid area codes for landlines and mobile (cell) phones are two digits (the first is 0). 08, 03 and 04 are all valid. 01 isn't. How do you cater for that? Do you want to?

Countries use different conventions no matter how many digits they're writing. You have to decide if you want to accept something other than the "norm". These are all common in Australia:

  • (02) 1234 5678
  • 02 1234 5678
  • 0411 123 123 (but I've never seen 04 1112 3456)
  • 131 123
  • 13 1123
  • 131 123
  • 1 300 123 123
  • 1300 123 123
  • 02-1234-5678
  • 1300-234-234
  • +44 78 1234 1234
  • +44 (0)78 1234 1234
  • +44-78-1234-1234
  • +44-(0)78-1234-1234
  • 0011 44 78 1234 1234 (0011 is the standard international dialling code)
  • (44) 078 1234 1234 (not common)

And thats just off the top of my head. For one country. In France, for example, its common the write the phone number in number pairs (12 34 56 78) and they pronounce it that way too: instead of:

un (one), deux (two), trois (three), ...

its

douze (twelve), trente-quatre (thirty four), ...

Do you want to cater for that level of cultural difference? I would assume not but the question is worth considering just in case you make your rules too strict.

Also some people may append extension numbers on phone numbers, possibly with "ext" or similar abbreviation. Do you want to cater for that?

Sorry, no code here. Just a list of questions to ask yourself and issues to consider. As others have said, a series of regular expressions can do much of the above but ultimately phone number fields are (mostly) free form text at the end of the day.

cletus
Character to digit mappings are consistent within each country where they are in wide use (or, stating the same: in countries where there is no consistent mapping, phone numbers will not be represented as letters). Since the country code is available, you also can identify *which* mapping is needed.
MSalters
Excellent post. By the way, we Mexicans also group (and pronounce) phone numbers in pairs. At least for me it's easier to memorize just 4 individual numbers rather than 8 (I tend to suffer with English phone numbers).
Joe Pineda
If you make your tel. no. formatter extend from java.text.Format, you'll be able to handle locale gracefully.
Chry Cheng
A: 

In some countries you can validate 112 as a valid phone number, but if you stick a country code in front of it it won't be valid any more. In other countries you can't validate 112 but you can validate 911 as a valid phone number.

I've seen some phones that put Q on the 7 key and Z on the 9 key. I've seen some phones that put Q and Z on the 0 key, and some that put Q and Z on the 1 key.

An area code that existed yesterday might not exist today, and vice-versa.

In half of North America (country code 1), the second digit rule used to be 0 or 1 for area codes, but that rule went away 10 years ago.

Windows programmer
+1  A: 

Thanks for the answers. As stated in the original question, I am much more interested in the formatting of the number into the standard format than I am in determining if it is a valid (as in genuine) phone number.

I have some hand crafted code currently that takes a phone number String (as entered by the user) and a source country context and target country context (the country from where the number is being dialed, and the country to where the number is being dialed - this is known to the system) and then does the following conversion in steps

  1. Strip all whitespace from the number

  2. Translate all alpha into digits - using a lookup table of letter to digit (e.g. A-->2, B-->2, C-->2, D-->3) etc. for the keypad (I was not aware that some keypads distribute these differently)

  3. Strip all punctuation - keeping a preceding '+' intact if it exists (in case the number is already in some sort of international format).

  4. Determine if the number has an international dialling prefix for the country context - e.g. if source context is the UK, I would see if it starts with a '00' - and replace it with a '+'. I do not currently check whether the digits following the '00' are followed by the international dialing code for the target country. I look up the international dialing prefix for the source country in a lookup table (e.g. GB-->'00', US-->'011' etc.)

  5. Determine if the number has a local dialing prefix for the country context - e.g. if the source context is the UK, I would look to see if it starts with a '0' - and replace it with a '+' followed by the international dialing code for the target country. I look up the local dialing prefix for the source country in a lookup table (e.g. GB-->'0', US-->'1' etc.), and the international dialing code for the target country in another lookup table (e.g.'GB'='44', US='1')

It seems to work for everything I have thrown at it so far - except for the +44(0)1234-567-890 situation - I will add a special case check for that one.

Writing it was not hard - and I can add special cases for each strange exception I come across. But I would really like to know if there is a standard solution.

The phone companies seem to deal with this thing every day. I never get inconsistent results when dialing numbers using the PSTN. For example, in the US (where mobile phones have the same area codes as landlines, I could dial +1-123-456-7890, or 011-1-123-456-7890 (where 011 is the international dialing prefix in the US and 1 is the international dialing code for the US), 1-123-456-7890 (where 1 is the local dialing prefix in the US) or even 456-7890 (assuming I was in the 123 area code at the time) and get the same results each time. I assume that internally these dialed numbers get converted to the same E.164 standard format, and that the conversion is all done in software.

Vihung
There's a potential flaw in step 5. It's possible that somewhere in the world there exist phone numbers where the area code can start with the same digit as the national dialling prefix (NB I don't know if there are, but I don't know there aren't either), and therefore you don't know if you're removing the prefix or removing part of the area code.(this isn't a problem with UK or US numbers)
grahamparks
A: 

I'm not aware of a standard library or framework available for formatting telephone numbers into E.164.

The solution used for our product, which requires formatting PBX provided caller-id into E.164, is to deploy a file (database table) containing the E.164 format information for all countries applicable. This has the advantage that the application can be updated (to handle all the strange corner cases in various PSTN networks) w/out requiring changes to the production code base.

The table contains a row for each country code and information regarding area code length and subscriber length. There may be multiple entries for a country depending on what variations are possible with area code and subscriber number lengths.

Using New Zealand PSTN (partial) dial plan as an example of the table..

CC  AREA_CODE  AREA_CODE_LENGTH  SUBSCRIBER  SUBSCRIBER_LENGTH
64                            1              7
64         21                 2              7
64        275                 3              6

We do something similar to what you have described, i.e. strip the provided telephone number of any non-digit characters and then format based on various rules regarding overall number plan length, outside access code, and long distance/international access codes.

Henk
How about this: CC cc AREA_CODE aa AREA_CODE_LENGTH n SUBSCRIBER what SUBSCRIBER_LENGTH 6 or 7. (I think I've also seen 7 or 8.)
Windows programmer
The shortened column names are reasonable, I was formatted this table as above purely for illustrative reasons. I'm unclear what the comments mean for the subscriber and sub length tho.
Henk
A: 

To be honest, it sounds like you've got most of the bases covered already.

The +44(0)800 format sometimes (incorrectly) used in the UK is annoying and isn't strictly valid according to E.123, which is the ITU-T recommendation for how numbers should be displayed. If you haven't got a copy of E.123 it's worth a look.

For what it's worth, the telephone network itself doesn't always use E.164. Often there'll be a flag in the ISDN signalling generated by the PBX (or in the network if you're on a steam phone) which tells the network whether the number being dialled is local, national or international.

Alnitak
A: 

The Joel's excellent code will work on the US based phone numbers. I was looking for it and it worked flawlessly.

udaman
I'm sure the code is excellent. However it does not answer the question which was about how to convert phone numbers into the international E.164 format
Vihung