This is part 1 of a 2 part post. In this part (part 1) we will compress a phone number for database storage. But what good is a compressed phone number stored away the remote darks of some database? This is where part 2 comes in. In that part we will break our phone number back up into its three parts to be formatted for display. More on that in a couple hours. First let’s compress it.
I built this UDF because I got tired of always manually having to add in special characters to remove from the original user entered phone number. Every time the client decided to type their phone number into the form field with new special characters I had to make an update I couldn’t charge for. No fun! After a few of these updates I decided it would be worth just writing a UDF that I could implement and forget forever. The client could write their phone numbers in any format they wished and no matter how off-the-wall this UDF would remove everything except the number itself.
A phone number is really just a sting of ten numbers unless you include the ’1′ at the beginning, and I don’t – so just ten numbers. (On this note, I should state that this UDF works only with U.S. phone numbers.) These ten numbers, and only these ten numbers is what we want to store as raw data. If we want the maximum front-end formatting flexibility we need to start with raw data, not pre-formatted phone number of someone you don’t even know.
As such, let’s look at the UDF. It’s posted here in its entirety so feel free to copy and paste it into your own CFC.
<cffunction name="compressPhoneNumber" displayname="Compress PhoneNumber" description="Compresses a phone number to remove formatting." access="public" output="false" returntype="struct"> <!--- PASS IN NUMBER TO BE COMPRESSED ---> <cfargument name="phonenumber" displayName="Phone Number" type="string" hint="Phone Number to be compressed." required="true" /> <!--- BUILD STRUCT ---> <cfset var number = structnew()> <cfset number.compressednumber = ARGUMENTS.phonenumber> <cfset number.originalnumber = ARGUMENTS.phonenumber> <cfset number.charary = arrayNew(1)> <cfset number.specialchars = arrayNew(1)> <cfset number.success = true> <cfset number.message = ""> <cftry> <!--- CREATEA BYTE ARRAY OF PASSED IN STRING ---> <cfset number.charary = ARGUMENTS.phonenumber.GetBytes()> <cfset number.aryLength = arrayLen(number.charary)> <!--- LOOP OVER ARRAY ---> <cfloop from="1" to="#number.aryLength#" index="VARIABLES.i"> <!--- IF NOT A NUMBER SET CHARACTER INTO A LIST ---> <cfif number.charary[VARIABLES.i] lt 48 OR number.charary[VARIABLES.i] gt 57> <cfset arrayAppend(number.specialchars, chr(number.charary[VARIABLES.i]))> </cfif> </cfloop> <!--- LOOP OVER SPECIAL CHARACTERS ARRAY AND REPLACE IT IN THE ORIGINAL STRING ---> <cfloop array="#number.specialchars#" index="VARIABLES.i"> <cfset number.compressednumber = replace(number.compressednumber, VARIABLES.i, "", "all")> </cfloop> <!--- CATCH ANY ERRORS ---> <cfcatch type="any"> <cfset number.success = false> <cfset number.message = "There was a problem compressing the number. Please refresh the page and try again."> </cfcatch> </cftry> <!--- RETURN STRUCT ---> <cfreturn number> </cffunction>
The method needs one thing and one thing only. The phone number to be compressed or have the extra formatting removed. Nothing too complicated happens with the number we pass in. The gist of it is that we need to determine what is not a number and then replace it with nothing. Although there are a couple ways to break a string down into its parts and pieces I prefer to break them down into their corresponding bytes. This way we can determine characters according to their byte code. Also another reason for using this method is the handy Java GetBytes() method. Although undocumented in Coldfusion you can dig down into the underlying Java and use its methods to do your bidding. In our case the GetBytes() method returns an array characters in byte format of the string that was passed to it. Just remember that Java is a heavily typed language and as such make sure that you use the toString() method to ensure that your phone number is string and not a number as it was intended to be. If for some reason you later needed it to be typed back as a number you can always use Java’s ParseInt() method to return it to a number, although this is probably not advisable for formatting reasons.
Moving on, we now have an array of byte code. Perfect. If we look at our ascii table of character codes we’ll see that the number ’0′ is represented as ’48′ in byte code and the number ’9′ is represented as ’57′ in byte code, and the other digits fall in-between. All we need to do is loop over the bytes, check if they fall between ’48′ and ’57′. If not we ditch them leaving us with just the number itself as a string.
I return the data in a struct that shows the original number, special characters that were removed from the string, and the compressed string. You could of course remove this struct and just return the string for a little performance gain, but thought you might like to see what’s happening behind the scenes a little.