Search the web for JavaScript scripts to format phone numbers and postal codes, and you'll find lots out there. The problem with most of the ones you find is that they are much more complex than they need to be, and do not handle different entry formats well. For example, entering phone numbers as "5551234" or "(888) 555-1234" requires different approaches. Regular Expressions can make this complexity much simpler, and reduce the amount of code needed.
My particular use case cropped up when I was setting up a new interface to for an application. Our users may (or may not) enter phone numbers and postal codes. The users may or may not use a consistent method for entering the data. We wanted to format the values properly if we could, but otherwise leave what the user entered in place. The troublesome part is that phone numbers may or may not be entered with an area code, and may use brackets, dashes, dots, or spaces for grouping/separators. Or there may be NO separation (i.e. 8881234567). Our formatting routine needed to handle these differences.
Enter Regular Expressions. I had picked up a copy of O'Reilly's Regular Expressions Cookbook some time ago, and knew it had some samples that addressed this problem. But, the samples were not quite what we needed. We didn't just want to know if a entered value was valid. We needed to extract the parts so we can drop them into a formatted output string. So, using the "recipes" from the cookbook as a starting point, we tweaked the regular expressions some, and came up with some simple JavaScript code to do what we needed. Here's the code, with a brief discussion afterwards:
/**
* Format phone numbers
*/
function formatPhone(phonenum) {
var regexObj = /^(?:\+?1[-. ]?)?(?:\(?([0-9]{3})\)?[-. ]?)?([0-9]{3})[-. ]?([0-9]{4})$/;
if (regexObj.test(phonenum)) {
var parts = phonenum.match(regexObj);
var phone = "";
if (parts[1]) { phone += "+1 (" + parts[1] + ") "; }
phone += parts[2] + "-" + parts[3];
return phone;
}
else {
//invalid phone number
return phonenum;
}
}
/**
* Format postal code
*/
function formatPostalcode(pcode) {
var regexObj = /^\s*([a-ceghj-npr-tvxy]\d[a-ceghj-npr-tv-z])(\s)?(\d[a-ceghj-npr-tv-z]\d)\s*$/i
if (regexObj.test(pcode)) {
var parts = pcode.match(regexObj);
var pc = parts[1] + " " + parts[3];
return pc.toUpperCase();
}
else {
return pcode;
}
}
Phone Numbers:
First we set up a regular expression object. This object will match the country dialing code (+1) if it exists, but then ignore it. We can "capture" the dialing code by removing the first "?:" from the expression, but this seems pointless - it will always be a "1". Then the expression captures the area code, and the two parts of the phone number. Next we do a test to see if the incoming string matches the regular expression. If not, we can assume the string is not a valid phone number, so we'll just spit out what was passed to the function. But, if we DO pass the test, then we have a valid phone number and can extract the parts, and then use those parts to build the desired output. We use the String.match() method to apply the regular expression and get an array of the matching parts. If the incoming string were "5551234", the area code will be "undefined". This is properly reflected in the array. So we can do a quick check to see if an area code exists and if so, add the desired elements to our output string. Finally, we add the two parts of the phone number separated by a dash, and return that from the function.
Postal Codes:
This code is similar to the phone number with a couple minor exceptions. First, the regular expression here was not taken from the O'Reilly Cookbook. Instead, it was found at http://home.cogeco.ca/~ve3ll/jstutorf.htm. We tried to start with the O'Reilly Cookbook's recipe, but found it only handled validation of a string that was already in the right format. We needed to handle "T2A 2A2" and "T2A2A2" type of entries. Finding an existing expression online was faster than trying to modify the expression. Even then though, we had to tweak the expression we found. We added some brackets so that we could "capture" the two parts of the postal code. Then just like the phone number routine, we used those parts to format the desired output string. If the incoming string does not appear to be a valid postal code, we just return what was entered.
These functions are not a silver bullet for EVERY possible use case. But, they do handle most cases I'm likely to run into.