Click here to Skip to main content
14,299,664 members

Advanced Phone Number Type Implementation

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


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).


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:

DAutomatically 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.
GAlias of "c-a-x-s e".
NPlain 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).
PPhonetic 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.
FAlias of "P (x-s)", or "D" if there is no phonetic string.
cAny place this character occurs in the format string will be replaced by the country code.
aAny place this character occurs in the format string will be replaced by the 3 digit NPA code.
xAny place this character occurs in the format string will be replaced by the 3 digit NXX code.
sAny place this character occurs in the format string will be replaced by the 4 digit station code.
eAny place this character occurs in the format string will be replaced by the extension code.
EAny place this character occurs in the format string will be replaced by the extension code prefixed by "ext ".
pAny 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.


  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


  • 24th December, 2008: Initial post


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


About the Author

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 Pin
karenpayne29-Dec-09 8:07
memberkarenpayne29-Dec-09 8:07 
RantIs not thread safe Pin
mindbener27-Feb-09 5:24
membermindbener27-Feb-09 5:24 
GeneralRe: Is not thread safe Pin
Flamewave427-Feb-09 9:11
memberFlamewave427-Feb-09 9:11 
GeneralFinally... Pin
Antonello Provenzano29-Jan-09 15:23
memberAntonello Provenzano29-Jan-09 15:23 
GeneralRe: Finally... Pin
Flamewave429-Jan-09 18:17
memberFlamewave429-Jan-09 18:17 
GeneralInteresting Pin
GibbleCH29-Dec-08 7:32
memberGibbleCH29-Dec-08 7:32 
QuestionDoesn't Work for me Pin
bhucodes25-Dec-08 18:21
memberbhucodes25-Dec-08 18:21 
AnswerRe: Doesn't Work for me Pin
User 665826-Dec-08 0:23
memberUser 665826-Dec-08 0:23 

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

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

Posted 24 Dec 2008


40 bookmarked