Today I thought I'd share a little ColdFusion helper function I've been using for years: structFilter(). The structFilter() parses a structure and returns only the keys that match a given regular expression.
<!--- Searches a structure for keys matching a regex and returns a structure containing the matched keys. @param input The structure to filter. (struct; required) @param regex The regular expression to filter keys against. (string; required) @param useNoCase Do a case insensitive search? (boolean; default = true) @param useDeepCopy Do a deep copy on the keys? (boolean; default = false) @return Returns a structure containing the matching keys. @author Dan G. Switzer, II (dan.switzer@givainc.com) @version 1, June 17, 2009 ---> <cffunction name="structFilter" returntype="struct" output="false" access="public" hint="Filters keys in a structure to those matching the regular expression."> <!---// define valid arguments //---> <cfargument name="input" type="struct" required="true" /> <cfargument name="regex" type="string" required="true" /> <cfargument name="useNoCase" type="boolean" required="false" default="true" /> <cfargument name="useDeepCopy" type="boolean" required="false" default="false" /> <!---// define local variables //---> <cfset var result = structNew() /> <!---// if using NoCase and the (?i) directive doesn't exist, append to regex //---> <cfif arguments.useNoCase and not reFind("^\(\?[mx]*i[mx]*\)", arguments.regex)> <cfset arguments.regex = "(?i)" & arguments.regex /> </cfif> <cfloop item="key" collection="#arguments.input#"> <cfif reFind(arguments.regex, key)> <cfif arguments.useDeepCopy> <cfset result[key] = duplicate(arguments.input[key]) /> <cfelse> <cfset result[key] = arguments.input[key] /> </cfif> </cfif> </cfloop> <!---// return the new structure //---> <cfreturn result /> </cffunction>
I've found this helper UDF to be extremely handy in when you have a bunch of serialized form fields that follow a given nomenclature. For example, if you have a bunch of form fields like:
<input type="text" name="name" value="" /> <input type="text" name="description" value="" /> <!---// dynamic list of variables //---> <cfloop index="i" from="1" to="10"> <cfoutput> <input type="text" name="id_#i#" value="" /> </cfoutput> </cfloop>
Using the structFilter() UDF you can vary easily process all the fields starting with "id_" by doing:
<!---// get all the fields: * starting with "id_" * and ending with one or more numbers //---> <cfset stIds = structFilter(form, "^id_\d+$") />
This will give you a structure containing all the "id_" fields that you can then process in a collection-based loop. This method is much more effective then passing in some kind of hidden "counter" variable where you loop from 1 to the counter variable (which is a technique I've used in the past) as it doesn't rely on the numbers being serialized.
There are obviously many other uses for this function, but I use it a lot for processing complex forms that have dynamically generated fields that have a fixed nomenclature.
2 Comments
Comments for this entry have been disabled.