Click here to Skip to main content
Click here to Skip to main content

Advanced Phone Number Type Implementation

, 24 Dec 2008 CPOL
Rate this:
Please Sign up or sign in to vote.
A phone number structure that can be used for parsing, validating, and normalizing phone numbers.

Introduction

There are many applications for the need to parse, normalize and validate phone numbers. This article provides a single structured type that allows you to easily parse, normalize, and validate NANP (North American Numbering Plan) phone numbers. It should support global phone numbers as well, but I haven't tested it with any global numbers. It also has support for phonetic phone numbers (such as 1-800-MY-PHONE).

Background

I have run into many situations where I have needed a simple and easy way to parse, normalize, and validate phone numbers from user input on web forms, thus the PhoneNumber structure was born. It started out as a simple structure that would only parse a limited number of formats, and over time I have added more advanced parsing abilities to it, and even added phonetic phone number support. It does still have a few limitations when parsing phone numbers with extension codes, but for the most part has been able to handle almost every format I've tossed at it.

The structure was originally built to normalize and validate NANP numbers only, but it should be able to handle international phone numbers as well. About the only exception would be if a country code uses an alpha-numeric code instead of just a numeric code.  I have not tested any international phone numbers with this structure though.

If you are interested in learning more about the NANP, good old Wikipedia is probably the best place to read about it.

Using the Code

The code file is fully documented and has quite a few examples included in it, so I will only provide some basic examples here to show off what the structure is capable of.

// Create a basic instance by specifying integer values.
PhoneNumber phone = new PhoneNumber(1, 800, 222, 2222, 1234);
Console.WriteLine(phone); // output: (800) 222-2222 ext 1234

// Create an instance by parsing a numerical string
PhoneNumber phone = new PhoneNumber("1-800-222-2222 ex 1234");
Console.WriteLine(phone); // output: (800) 222-2222 ext 1234

// Create an instance by parsing a phonetic phone number
PhoneNumber phone = new PhoneNumber("800 MY-TEST ex 1234", true);
Console.WriteLine(phone); // output: (800) MY-TEST ext 1234

// Check if a phone number is NANP valid
PhoneNumber phone = new PhoneNumber("(800) 222.2222");
Console.WriteLine("Is NANP valid? {0}", phone.IsNanpValid);

The output format above is using the default format output (the "P" format string), but the output can be customized to pretty much any format you want. Here is an overview of format strings that are accepted:

Token Description
D Automatically formats the phone number based on its values. Possible formats: c-a-x-s E, c-a-x-s, (a) x-s, (a) x-s E, x-s E, and x-s.
G Alias of "c-a-x-s e".
N Plain numerical phone number, with no special formatting characters (same as caxs e and/or caxs and/or axs e and/or axs and/or xs e and/or xs).
P Phonetic representation, if a phonetic string is specified. If there is no phonetic string, this format string acts the same as the "D" format string. Possible formats: c-a-p E, c-a-p, (a) p E, (a) p, p E, p, c-a-x-s E, c-a-x-s, (a) x-s E, (a) x-s, x-s E, and x-s.
F Alias of "P (x-s)", or "D" if there is no phonetic string.
c Any place this character occurs in the format string will be replaced by the country code.
a Any place this character occurs in the format string will be replaced by the 3 digit NPA code.
x Any place this character occurs in the format string will be replaced by the 3 digit NXX code.
s Any place this character occurs in the format string will be replaced by the 4 digit station code.
e Any place this character occurs in the format string will be replaced by the extension code.
E Any place this character occurs in the format string will be replaced by the extension code prefixed by "ext ".
p Any place this character occurs in the format string will be replaced by the phonetic representation of the phone number. If there is no phonetic string, this format string is the same as "x-s". If the phonetic string is not seven characters, then the NPA and NXX codes are used to make it seven characters.

All other characters are left as-is. Note that tokens are cap-sensitive.

Points of Interest

I originally started out using a regular expression to parse the phone number from a string, but after adding more and more flexibility to the formats, the expression became a garbled unreadable mess, so I opted to go for the more readable and flexible, but slightly slower manual parsing. All of the parsing work is done in the private member _Parse().

If you want to use this structure to scrub a database of phone numbers and normalize them, you will probably want to edit the _Parse function to relax its restrictions a little. I've noticed several times when I've scrubbed a database, I've had to comment out the spot where it checks to make sure there are no more than seven phonetic characters (lines 1306 - 1309) and also the spot where it checks an array of allowed characters in order to get it to successfully scrub all of the database values (lines 1317 - 1320).

The structure implements the IComparable, IFormattable, and ISerializable interfaces and also provides operator overrides for ==, !=, <, >, <=, and >=. I have also provided a type converter for the structure, although I haven't had a chance to fully test it yet.

I didn't provide a project/solution file because I use MonoDevelop (yes, I am developing .NET in a Linux environment), and figured including the MonoDevelop project/solution files would be useless for most people. The PhoneNumberTest.cs file is just a simple console application that shows how to use the structure. All of the examples on how to use the code are in the documentation in the PhoneNumber.cs file.

TODO

  1. Implement a ParseExact() method (much like the DateTime.ParseExact() method)
  2. Implement a TryParseExact() method (like the DateTime.TryParseExact() method)
  3. Test and make sure that the structure supports international phone numbers, and possibly add international validation
  4. Improve the extension parsing to be less restrictive

History

  • 24th December, 2008: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Flamewave4
Web Developer Onsharp
United States United States
I have been developing websites since 1999, and occasionally will venture into application development. I am proficient in most of the web-based languages and love what I do. I work for a small web development firm based out of Fargo, ND and plan to stay in the web development business for a long time. When I'm not programming I enjoy hiking, biking, woodworking, yard work, and the occasional computer/console game.

Comments and Discussions

 
GeneralThanks PinmemberGlimmerMan29-Dec-09 9:07 
RantIs not thread safe Pinmembermindbener27-Feb-09 6:24 
GeneralRe: Is not thread safe PinmemberFlamewave427-Feb-09 10:11 
GeneralFinally... PinmemberAntonello Provenzano29-Jan-09 16:23 
GeneralRe: Finally... PinmemberFlamewave429-Jan-09 19:17 
GeneralInteresting PinmemberGibbleCH29-Dec-08 8:32 
QuestionDoesn't Work for me Pinmemberbhucodes25-Dec-08 19:21 
AnswerRe: Doesn't Work for me PinmemberGreeeg26-Dec-08 1:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141223.1 | Last Updated 24 Dec 2008
Article Copyright 2008 by Flamewave4
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid