REStructFindValue() - Adding Regular Expression Searching To StructFindValue()

<cffunction
	name="reStructFindValue"
	access="public"
	returntype="array"
	output="false"
	hint="I search for patterns within a given ">
 
	<!--- Define arguments. --->
	<cfargument
		name="target"
		type="any"
		required="true"
		hint="I am the target struct being searched."
		/>
 
	<cfargument
		name="pattern"
		type="string"
		required="true"
		hint="I am the pattern being searched."
		/>
 
	<cfargument
		name="scope"
		type="string"
		required="false"
		default="one"
		hint="I am the scope of the search: one or all."
		/>
 
	<cfargument
		name="path"
		type="string"
		required="false"
		default=""
		hint="The path to the current target (for recursive calling). ** NOTE: This is used internally for recursion - this is NOT an expected argument to be passed in by the user."
		/>
 
	<!--- Define the local scope. --->
	<cfset var local = {} />
 
	<!--- Create an array --->
	<cfset local.results = [] />
 
	<!---
		Loop over target.
		NOTE: This uses a ColdFusion custom tag that unifies
		the interface for looping over both structure and
		arrays.
		http://www.bennadel.com/go/each-iteration
	--->
	<cf_each
		item="local.item"
		collection="#arguments.target#">
 
		<!--- Create a variable to store the base path. --->
		<cfset local.path = arguments.path />
 
		<!--- Add the current key to the path. --->
		<cfset local.path &= "[ ""#local.item.key#"" ]" />
 
		<!--- Get a handle on the new target. --->
		<cfset local.target = local.item.value />
 
		<!---
			Check to see if this new target is a string (or
			if it is another complex object that we need to
			iterate over).
		--->
		<cfif isSimpleValue( local.target )>
 
			<!---
				Check it for the pattern match on the target
				value. For now, we are going to be using
				ColdFusion's Match() method which means a sub
				set of regular expression usage. Furthermore,
				we are going to use NoCASE for each of coding.
			--->
			<cfif arrayLen( reMatchNoCase( arguments.pattern, local.target ) )>
 
				<!---
					The regular expression patther was found at
					least once in the target value. This is a
					valid match. Add it to the results.
				--->
				<cfset local.result = {
					key = local.item.key,
					owner = arguments.target,
					path = local.path
					} />
 
				<!--- Add this result to the current results. --->
				<cfset arrayAppend( local.results, local.result ) />
 
			</cfif>
 
		<!---
			Make sure this complex nested target is one that
			we can actually iterate over (all others will be
			skipped).
		--->
		<cfelseif (
			isStruct( local.target ) ||
			isArray( local.target )
			)>
 
			<!---
				The nested taret is not a simple value. Therefore,
				we need to perform a depth-first, recusive search
				of it for our matching pattern.
			--->
			<cfset local.childResults = reStructFindValue(
				local.target,
				arguments.pattern,
				arguments.scope,
				local.path
				) />
 
			<!---
				Add the results from our nested search to the
				current results collection.
			--->
			<cfloop
				index="local.childResult"
				array="#local.childResults#">
 
				<!--- Add this result to the current results. --->
				<cfset arrayAppend( local.results, local.childResult ) />
 
			</cfloop>
 
		</cfif>
 
 
		<!---
			At the end of a single iteration, let's check to see
			if we were only searching for one target. If we are,
			AND we found it, we can simply return the single
			element rather than continuing on with our recursion.
		--->
		<cfif (
			(arguments.scope eq "one") &&
			arrayLen( local.results )
			)>
 
			<!---
				We found at least one item - trim the results
				set in case the last iteration found more than
				one.
			--->
			<cfset local.trimmedResults = [ local.results[ 1 ] ] />
 
			<!--- Return the trimmed result set. --->
			<cfreturn local.trimmedResults />
 
		</cfif>
 
	</cf_each>
 
 
	<!--- Return the found results. --->
	<cfreturn local.results />
</cffunction>

For Cut-and-Paste