DEV Community

James Moberg
James Moberg

Posted on

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>
Retry later

Top comments (0)

Retry later
Retry later