Phone Number Validation
By eSamuraiAt some point in time every web developer will need to validate the form fields email and phone number. The better methods for validating both of these fields require the use of a regular expression, and most of the web developers I know will do a quick Google search to find a regular expression and move on. This method will work for the most part — especially for email. When it comes to regular expression and validating, I rarely do a Google search but just write one myself. If you do do a Google search most of the regular expressions are going to simply match the (XXX) XXX-XXXX pattern. Some may require that exact pattern, others may be more flexible allowing different delimiters, optional parenthesis/delimiters, and so on. I haven’t seen any that actually go beyond that. I wonder if anyone else has really considered that possibility that one could go beyond that. So when I needed to validate phone numbers I didn’t search Google for the regular expression, instead I searched for information about telephone numbering plans. I found a lot of information, but since the websites I deal with cater mostly to North America I limited my research to just the North American Numbering Plan (NANP). What I eventually ended up with, was a phone number class that not only checks if the numbers fit the simple pattern above, but if the numbers themselves were legal entries based on the standards set forth in the NANP. As stated in the Wikipedia article above:
Current NANP number format can be summed up via the following:
+1-NPA-NXX-xxxx
If you’re curious as to what that means, I suggest reading the Wikipedia article. The algorithm I came up with is:
- Parse number into area code and the phone number.
Regular Expression: ^\(?(\d{3})\)?[\s.-]*([0-9]{3}[. -]?[0-9]{4})$ - Validate the area code.
Regular Expression: ^\(?[2-9][0-8][0-9]\)?$ - Validate the phone number.
Regular Expression: ^[2-9](1(?!1)|[02-9])[0-9](?(?< =555)[. -]?(?!01)[0-9]{4}|[. -]?[0-9]{4})$
I created an IPhoneNumber interface and then created a NorthAmericanPhoneNumber class that implements IPhoneNumber. That way, if I ever need to support other phone numbering plans, I can easily add in the functionality. The interface is very simple:
public interface IPhoneNumber
{
string CountryCode { get; set; }
[Required]
string AreaCode { get; set; }
[Required]
string Number { get; set; }
}
The implementation of the North American phone number, isn’t that difficult either:
public class NorthAmericanPhoneNumber : IPhoneNumber
{
public static bool IsValid(string number)
{
try
{
Parse(number);
return true;
}
catch
{
return false;
}
}
public static IPhoneNumber Parse(string number)
{
var phoneNumber = new NorthAmericanPhoneNumber();
var parts = Regex.Matches(number, @"^\(?(\d{3})\)?[\s.-]*([0-9]{3}[. -]?[0-9]{4})$");
if (parts.Count > 0)
{
phoneNumber.AreaCode = parts[0].Groups[1].Value;
phoneNumber.Number = parts[0].Groups[2].Value;
}
return phoneNumber;
}
private string areaCode;
private string number;
public string CountryCode
{
get { return "+1"; }
set { }
}
public string AreaCode
{
get { return areaCode; }
set
{
Regex npa = new Regex(@"^\(?[2-9][0-8][0-9]\)?$");
if (npa.IsMatch(value))
areaCode = value;
else
throw new ArgumentException(String.Format("{0} is not a valid North American Area Code.", value));
}
}
public string Number
{
get { return number; }
set
{
Regex valid = new Regex(@"^[2-9](1(?!1)|[02-9])[0-9](?(?< =555)[. -]?(?!01)[0-9]{4}|[. -]?[0-9]{4})$");
if (valid.IsMatch(value))
number = value;
else
throw new ArgumentException(String.Format("{0} is not a valid North American phone number.", value));
}
}
public override string ToString()
{
if (areaCode != null && number != null)
{
var exchange = number.Substring(0, 3);
var local = number.Substring(number.Length - 4);
return String.Format("({0}) {1}-{2}", areaCode, exchange, local);
}
return String.Empty;
}
}
The IsValid function is static, and can be used anywhere to validate phone numbers. Notice that it’s validation is done by trying to assign the supplied number to the area code and phone number properties. If the number supplied is invalid, an exception will be thrown during assignment which is caught causing false to be returned by the function. I also overrided the ToString() function so that it will output the phone number in the normal format.
If anyone finds this helpful, I’d love to hear about it. I ask that if anyone goes on to implement any other regional phone numbers to please share the link to it.

NorthAmericanPhoneNumber by Brian Cupples is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.