DEV Community

Cover image for phoneFormat & makeTelLink ColdFusion UDFs
James Moberg
James Moberg

Posted on

1

phoneFormat & makeTelLink ColdFusion UDFs

Standardization & validation is important, but good luck getting all you clients and your client's visitors on board with adhering to ISO standards. When it comes to phone numbers, we've embraced the E.164 international standard (ITU-T recommendation) in order to simplify integration with third-party SMS services (like Twilio), but that doesn't mean our clients like to see phone numbers in that format. When it comes to cosmetically formatting phone numbers, I personally prefer the (223) 456-7890 format, but some design-orientated clients demand that we use 123.456.7890 which I think more closely resembles an IP address.

In order to make our lives easier and quickly adapt when our clients change their minds (which tends to happen more than you'd think), we use dynamic server-side formatting for phone number data.

Apparently there are a lot of different ways to format phone numbers. The Gregg Reference Manual offers many possibilities (as referenced in this article.)

SalesForce has special logic formatting for the phone field to provide automatic formatting. I also found a blog with a decent article entitled "Why You Should Care About Phone Number Formatting In Your CRM (and How to Fix Them)" with some examples of phone number variations.

  • 2124567890
  • 212-456-7890
  • (212)456-7890
  • (212)-456-7890
  • 212.456.7890
  • 212 456 7890
  • +12124567890
  • +12124567890
  • +1 212.456.7890
  • +212-456-7890
  • 1-212-456-7890

I've been using a CFLib phoneFormat library to reformat US phone numbers and had made some tweaks to it over the years. To provide even better value for mobile users, we use a CFML script to attempt to detect mobile browsers and then auto-generate clickable TEL links on webpages using a makeTelLink UDF. (For more info regarding TEL, check out MSDN or IETF.)

In cases where the phone number may not match a US pattern, the phoneFormat string is returned unchanged while makeTelLink returns a non-linked string.

UPDATE 2024-11-15: Added optional support in both UDFs for phone extensions (off by default).

Enjoy!

Source Code for phoneFormat & makeTelLink

https://gist.github.com/JamoCA/4342da7f2388a3a0b38fb6b55b8c9c35

<cfscript>
/* PhoneFormat ColdFusion UDF
7/22/2010 Original from http://cflib.org/udf/phoneFormat
Allows you to specify the mask you want added to your phone number.
v2 - code optimized by Ray Camden
v3.01
v3.02 added code for single digit phone numbers from John Whish
v4 make a default format - by James Moberg
@param input Phone number to be formatted. (Required)
@param mask Mask to use for formatting. x represents a digit. (Required)
@author Derrick Rapley (adrapley@rapleyzone.com)
@version 3, May 9, 2009
@version 4, February 11, 2011
2014-01-14 Updated by James Moberg @ SunStarMedia.com (exit if alpha or not enough digits)
2024-11-15 Add support for extension
Author: James Moberg http://sunstarmedia.com @sunstarmedia
GIST: https://gist.github.com/JamoCA/4342da7f2388a3a0b38fb6b55b8c9c35
Blog: https://dev.to/gamesover/phoneformat-maketellink-coldfusion-udfs-40fh
X/Twitter: https://x.com/gamesover/status/1857119411058201026
LinkedIn: https://www.linkedin.com/posts/jamesmoberg_coldfusion-cfml-activity-7262886030020665345-MWwn
*/
string function phoneFormat(string varInput="", string varMask="(xxx) xxx-xxxx", boolean allowExtension=false, string extPrefix="x") hint="Allows you to specify the mask you want added to your phone number." {
local.input = trim(arguments.varInput).replaceAll("^1","").replaceAll("^(\+1|1[\s\-\(\.])", "");
local.mask = (len(trim(arguments.varMask)) && find("x", arguments.varMask)) ? arguments.varMask : "(xxx) xxx-xxxx";
// identify & standardize extension
local.ext = "";
if (arguments.allowExtension && listlen(local.input, "x") eq 2 && len(trim(listlast(local.input, "x")))){
local.input = local.input.replaceAll("(?i)(ext\.?|extension)", "x");
local.ext = listlast(local.input, "x").replaceAll("\D", "");
if (len(local.ext)){
local.ext = " " & arguments.extPrefix & local.ext;
local.input = trim(listfirst(local.input, "x"));
}
}
local.newFormat = javacast("string", local.input).replaceAll("\D", "");
if (refind("\+[^1]", local.input)){
return trim(arguments.varInput); // international (non-US) phone number
}
if (refind("[a-w]|y|z|[A-Z]", local.input)){
return trim(arguments.varInput); // contains alpha characters;
}
if (len(local.newFormat) neq len(local.mask.replaceAll("(?i)[^x]", ""))){
return trim(arguments.varInput); // Not enough digits
}
local.input = trim(local.input);
local.newFormat = " " & local.input.replaceAll("\D", "");
local.newFormat = reverse(local.newFormat);
local.mask = reverse(local.mask);
for (local.i=1; local.i lte len(trim(local.mask)); local.i+=1) {
local.curPosition = mid(local.mask, local.i, 1);
if(local.curPosition neq "x") {
local.newFormat = insert(local.curPosition, local.newFormat, local.i-1) & " ";
}
}
return trim(reverse(local.newFormat)) & local.ext;
}
</cfscript>
<cfscript>
/* Examples for phoneFormat & makeTelLink ColdFusion UDFs
Test phone numbers from https://blog.insycle.com/phone-number-formatting-crm
Author: James Moberg http://sunstarmedia.com @sunstarmedia
Ref: Salesforce Standard 'Phone' field length and formatting https://help.salesforce.com/s/articleView?id=000385963&type=1
Ref: Business writing https://www.businesswritingblog.com/business_writing/2007/01/how_to_format_p.html
Ref: https://stackoverflow.com/questions/9482633/how-do-i-include-extensions-in-the-tel-uri
GIST: https://gist.github.com/JamoCA/4342da7f2388a3a0b38fb6b55b8c9c35
Blog: https://dev.to/gamesover/phoneformat-maketellink-coldfusion-udfs-40fh
X/Twitter: https://x.com/gamesover/status/1857119411058201026
LinkedIn: https://www.linkedin.com/posts/jamesmoberg_coldfusion-cfml-activity-7262886030020665345-MWwn
*/
tests = [
"+12124567890", // E.164 standard (no spaces, no dashes, no parenthesis, and no periods)
"2124567890",
"212-456-7890",
"(212)456-7890",
"(212)-456-7890",
"212.456.7890",
"212 456 7890",
"+1 212.456.7890",
"12124567890",
"1212-456-7890",
"1(212)456-7890",
"1(212)-456-7890",
"1.212.456.7890",
"1 212 456 7890",
"1 212 456 7890 x203",
"1 212 456 7890 x 203",
"1 212 456 7890 ext. 203",
"1 212 456 7890 extension 203",
"+212-456-7890", // If you do not want the parentheses-space-hyphen formatting (800) 555-1212 for a 10- or 11-digit number, enter a “+” before the number.
"21256789012", // extra digit
"678-9012" // local; not enough info
];
for (phoneNumber in tests){
writeoutput("<div>#phoneNumber# = #phoneFormat(varInput=phoneNumber, allowExtension=true)#.");
writeoutput(" Call us #makeTelLink(n=phoneNumber, forceTel=true, mask=true, allowExtension=true)#.</div>");
}
</cfscript>
view raw tests.cfm hosted with ❤ by GitHub

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Immerse yourself in a wealth of knowledge with this piece, supported by the inclusive DEV Community—every developer, no matter where they are in their journey, is invited to contribute to our collective wisdom.

A simple “thank you” goes a long way—express your gratitude below in the comments!

Gathering insights enriches our journey on DEV and fortifies our community ties. Did you find this article valuable? Taking a moment to thank the author can have a significant impact.

Okay