<cffunction name="ApplyTextMap" access="public" returntype="string" output="false" hint="Applies the given map (name-value structure) to the given text value."> <!--- Define arguments. ---> <cfargument name="Text" type="string" required="true" hint="The text to which we will be applying the text map." /> <cfargument name="Map" type="struct" required="true" hint="The struct containing the key-value text mappings." /> <!--- Define the local scope. ---> <cfset var LOCAL = StructNew() /> <!--- Set up a local copy of the string. ---> <cfset LOCAL.Text = ARGUMENTS.Text /> <!--- We are going to make repeated use of several Java objects. Therefore, let's create the static classes here that we can then use later for construction. NOTICE: We are not calling INIT as we only want the static version of the Java classes. ---> <cfset LOCAL.StringBufferClass = CreateObject( "java", "java.lang.StringBuffer" ) /> <!--- Regular expressoin pattern class. ---> <cfset LOCAL.PatternClass = CreateObject( "java", "java.util.regex.Pattern" ) /> <!--- We are going to use a regular expression iterator to loop over all the values in string and perform the replace. No matter what, though, we have to loop over all values in the struct. ---> <cfloop item="LOCAL.Key" collection="#ARGUMENTS.Map#"> <!--- We need to prepare the key for our search. Even though we are using the regular expression pattern matcher, we don't want the key to have any regular expression properties. Therefore, we need to escape all special characters. ---> <cfset LOCAL.Key = LOCAL.Key.ReplaceAll( "([\+\*\{\}\[\]\(\)\?\\\$]){1}", "\\$1" ) /> <!--- Create the string buffer that will hold the temporary results of the text changes made by this map-application iteration. ---> <cfset LOCAL.Buffer = LOCAL.StringBufferClass.Init() /> <!--- Create the pattern we are matching. Use the case-insensitive flag. ---> <cfset LOCAL.Pattern = LOCAL.PatternClass.Compile( "(?i)\b#LOCAL.Key#\b" ) /> <!--- Get the matcher for this pattern. ---> <cfset LOCAL.Matcher = LOCAL.Pattern.Matcher( LOCAL.Text ) /> <!--- Now that we have our matcher, let's keep iterating over the matcher while we can find instances of the pattern in the target text (that we must replace). ---> <cfloop condition="LOCAL.Matcher.Find()"> <!--- Replace the current match with value in the text map. When performing the match, we have to make sure that it has no regular expression parts. ---> <cfset LOCAL.Matcher.AppendReplacement( LOCAL.Buffer, ToString( ARGUMENTS.Map[ LOCAL.Matcher.Group() ] ).ReplaceAll( "(\\|\$){1}", "\\$1" ) ) /> </cfloop> <!--- We have replaced all instances of the given pattern. Now, just append what ever we didn't already put in the buffer. ---> <cfset LOCAL.Matcher.AppendTail( LOCAL.Buffer ) /> <!--- Now that we have completely replaced the current term in the text map, let's save the results back into the local text result for the next iteration. ---> <cfset LOCAL.Text = LOCAL.Buffer.ToString() /> </cfloop> <!--- Return the modified arguments. ---> <cfreturn LOCAL.Text /> </cffunction>