Handling phone numbers

I’m often asked questions about the handling and parsing of phone numbers, so I’m going to explain how we do it on Maemo 5. I hope this can be useful also for developers of other applications.

There is no unique standardised way to write phone numbers; in the UK the phone number of the Buckingham Palace Visitor Office can be written as 02073212233, +44 (0)20 7321 2233, 0044 207 321 2233, etc. If you omit the international prefix +44, the number 02073212233 could be used by somebody else in another country, for instance to me it looks like a phone number for somebody living in Milan.

When storing a phone number you should keep it as you got it, including spaces, parenthesis, etc.
When you want to use the number you should drop all the useless characters, but keep the extensions numbers. For instance 44-555-P1 would become 44555P1, which means: call the Vodafone UK balance information number 44555, pause for some seconds waiting for the recorded voice to start speaking, and send a 1 (i.e. ask for a text message with the remaining minutes for this month).

When comparing phone numbers to see if they belong to the same contact you also want to strip all the extra digits sent after a pause as those are not really part of the phone number. At this point you still have to somehow handle the craziness of international and local prefixes, for instance all these numbers could be a valid way to call the same person in San Marino: 0549 123 456, +378 0549 123 456, +39 0549 123 456, 0039 0549 123 456, 011 39 0549 123 456.
How do phones handle this? Just by comparing the last 7 digits of the phone number, that is the minimum length used somewhere for phone numbers.
This of course leaves a chance of false matches, but as you can see there is no real generic solution for this.

Here’s some code to show how to handle phone numbers. I used Python as a sort of pseudo-language, so I preferred readability for non-Python developers over good pythonic code.

extension_chars = ('p', 'P', 'w', 'W', 'x', 'X')

def normalize_phone_number(number):
    common_delimiters = (',', '.', '(', ')', '-', ' ',
                         't', '/')
    valid_digits = ('#', '*', '0', '1', '2', '3', '4',
                    '5', '6', '7', '8', '9')

    normalized = ''

    for digit in number:
        if digit in extension_chars:
            # Keep the extension characters P, W and X,
            # but be sure they are upper case.
            digit = digit.upper()
        elif digit == '+':
            # "+" is valid only at the beginning of phone
            # numbers or after the number suppression
            # prefix. (No idea why we support only this
            # GSM code, but not the VSC ones.)
            if normalized not in ('', '*31#', '#31#'):
                print 'Wrong "+" in "%s"' % number
                # Skip this "+".
        elif digit in common_delimiters:
            # Skip this delimiter.
        elif digit in valid_digits:
            # Ok, let's keep it.
            # What is this? It doesn't seem valid but we
            # just keep it
            print 'Unknown character "%s" in "%s"' % 
                    (digit, number)

        normalized += digit

    return normalized

def remove_extension_chars(number):
    clean = ''

    for digit in number:
        if digit in extension_chars:
            # Extension character, drop this character and
            # the rest of the string.

        clean += digit

    return clean

def phone_numbers_equal(number1, number2):
    number1 = normalize_phone_number(number1)
    number1 = remove_extension_chars(number1)

    number2 = normalize_phone_number(number2)
    number2 = remove_extension_chars(number2)

    # Compare only the last 7 digits.
    # If one of the numbers is shorter than 7 digits it's
    # important that the comparison is done on the full
    # length of the numbers and not only on the last tiny
    # bits of the 2 numbers.
    return number1[-7:] == number2[-7:]

Python code for handling phone numbers
(Download the full code with tests)

If you are handling phone numbers on Maemo 5, there are already some useful functions to use: e_​normalize_​phone_​number, osso_​abook_​phone_​numbers_​equal, osso_​abook_​contact_​matches_​phone_​number and osso_​abook_​query_​phone_​number.