DEV Community

James Moberg
James Moberg

Posted on

2 1

TokenReplace - A ColdFusion User-Defined Function

I've worked with different projects that perform tokenization differently; often it involves using different delimiters. While researching I saw that Drupal (which I don't use) has an official TokenReplace function documented in their API. I thought I'd write something similar since this this doesn't appear to be a function that Adobe ColdFusion currently has.

Usage

Create a string with tokens.

Here are some samples. (I don't personally recommend using HTML brackets, pound signs or parenthesis, but some frameworks use them.)

Hello {name}?  Is this {address}?  I have a special delivery for '{ccName}'.
Hello [name]?  Is this [address]?  I have a special delivery for '[ccName]'.
Hello <name>?  Is this <address>?  I have a special delivery for '<ccName>'.
Hello :name:?  Is this :address:?  I have a special delivery for ':ccName:'.
Hello <<name>>?  Is this <<address>>?  I have a special delivery for '<<ccName>>'.
Hello ::name::?  Is this ::address::?  I have a special delivery for '::ccName::'.
Hello #name#?  Is this #address#?  I have a special delivery for '#ccName#'.
Hello %name%?  Is this %address%?  I have a special delivery for '%ccName%'.
Hello -name-?  Is this -address-?  I have a special delivery for '-ccName-'.
Enter fullscreen mode Exit fullscreen mode

Create a data structure.

(NOTE: The token is not case-sensitive.)

replacementData = {
  "name" = "Bruce Wayne",
  "Address" = "1007 Mountain Drive, Gotham",
  "ccName" = "The Dark Night"
}
Enter fullscreen mode Exit fullscreen mode

Use the UDF

TokenReplace(Text, replacementData, "{", "}")
// Hello Bruce Wayne?  Is this 1007 Mountain Drive, Gotham?  I have a special delivery for 'The Dark Night'.
Enter fullscreen mode Exit fullscreen mode

NOTE: ReEscape may be an Adobe ColdFusion-only function, but BlueDragon supports it too. I'm not sure what the equivalent Lucee function is. (UPDATE: I replaced the ACF built-in function with the REEscape UDF from CFLib.)

TryCF Demo

https://trycf.com/gist/18e4d1662e8417fc824e264b2490dd1b

Source

https://gist.github.com/JamoCA/18e4d1662e8417fc824e264b2490dd1b

<!--- TokenReplace - replaces tokens in a string with data from a struct
2/27/2020 James Moberg https://www.sunstarmedia.com/
GIST: https://gist.github.com/JamoCA/18e4d1662e8417fc824e264b2490dd1b
Blog: https://dev.to/gamesover/tokenreplace-a-coldfusion-user-defined-function-155b
TryCF: https://trycf.com/gist/18e4d1662e8417fc824e264b2490dd1b
3/2/2020 Updated ReplaceList() to support 5 params so it works w/Lucee.
--->
<cfscript>
string function TokenReplace(required string Text, required struct data, string startBracket = "[", string endBracket = "]", boolean clearEmpty=false) output=false hint="replaces tokens in a string with data from a struct" {
var response = javacast("string", arguments.text);
var tokens = [];
var token = "";
var cleanTag = "";
var test = "";
var pos = 0;
var oldPos = 1;
var special_char_list = "\,+,*,?,.,[,],^,$,(,),{,},|,-";
var esc_special_char_list = "\\,\+,\*,\?,\.,\[,\],\^,\$,\(,\),\{,\},\|,\-";
var escStart = ReplaceList(arguments.startBracket, special_char_list, esc_special_char_list);
var escEnd = ReplaceList(arguments.endBracket, special_char_list, esc_special_char_list);
test = REFind("(#escStart#.+?#escEnd#)", response, 1, 1);
pos = test.pos[1];
while(pos gt 0) {
arrayAppend(tokens, mid(response, pos, test.len[1]));
oldpos = pos+test.len[1];
test = REFind("(#escStart#.+?#escEnd#)", response, oldPos, 1);
pos = test.pos[1];
}
for (token in tokens){
cleanTag = trim(replacelist(token, "#arguments.startBracket#,#arguments.endBracket#", ",", ",", true));
if (StructKeyExists(arguments.data, cleanTag) AND isSimplevalue(arguments.data["#cleanTag#"])){
response = response.replaceAll("(?i)#escStart##cleanTag##escEnd#", arguments.data["#cleanTag#"]);
} else if (arguments.clearEmpty){
response = response.replaceAll("(?i)#escStart##cleanTag##escEnd#", "");
}
}
return response;
}
</cfscript>
<h2>TokenReplace UDF Demo</h2>
<CFSET DelimiterData = [
["[", "]"],
["{", "}"],
["<", ">"],
[":", ":"],
["<<", ">>"],
["::", "::"],
["##", "##"],
["%", "%"],
["-", "-"]
]>
<cfset replacementData = {
"name" = "Bruce Wayne",
"Address" = "1007 Mountain Drive, Gotham",
"ccName" = "The Dark Night"
}>
<cfoutput>
<cfloop array="#DelimiterData#" INDEX="Delimiters">
<cfset Text = "Hello #Delimiters[1]#name#Delimiters[2]#? Is this #Delimiters[1]#address#Delimiters[2]#? I have a special delivery for '#Delimiters[1]#ccName#Delimiters[2]#'.">
<fieldset><legend>Delimiters: #EncodeforHTML(ArrayToList(Delimiters))#</legend>
<xmp>#Text#</xmp>
<div>#TokenReplace(Text, replacementData, Delimiters[1], Delimiters[2], true)#</div>
</fieldset>
</cfloop>
</cfoutput>

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

Speedy emails, satisfied customers

Postmark Image

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay