-
Notifications
You must be signed in to change notification settings - Fork 24
File Pattern Matcher
Available in Mach-II 1.9+
The MachII.util.matching.FileMatcher
is a specialty utility that performs a pattern match against a group of files and filters the results. The results are a CFML query data type and has the same columns as results returned by cfdirectory
(including two additional columns we're discuss more later).
In all reality, the File Pattern Matcher is a specialized version of the ANT Style Pattern Matcher that works with results from cfdirectory
. This matcher is one of the main utilities that drive View Loaders that was introduced in Mach-II 1.8.
The utility uses three different wildcards.
Wildcard | Description |
---|---|
* |
Matches zero or more characters. |
? |
Matches exactly one character. |
** |
Matches zero or more directories. |
<tr>
<td style="text-align: left">
<tt>/views/products/**/*.cfm</tt>
<br />
<tt>.</tt>
</td>
<td>
<em>Matches:</em><br />
/views/products/index.cfm<br />
/views/products/SE10/index.cfm<br />
/views/products/SE10/details.cfm<br />
/views/products/ST80/index.cfm<br />
/views/products/ST80/details.cfm<br />
<br />
<em>Does Not Match:</em><br />
/views/index.cfm<br />
/views/aboutUs/index.cfm<br />
/views/aboutUs/managementTeam.cfm
</td>
</tr>
<tr>
<td>
<tt>/views/**/*.cfm</tt>
<br />
<tt>.</tt>
</td>
<td>
<em>Matches:</em><br />
/views/index.cfm<br />
/views/aboutUs/index.cfm<br />
/views/aboutUs/managementTeam.cfm<br />
/views/products/index.cfm<br />
/views/products/SE10/index.cfm<br />
/views/products/SE10/details.cfm<br />
/views/products/ST80/index.cfm<br />
/views/products/ST80/details.cfm<br />
<br />
<em>Does Not Match:</em><br />
/views/index.htm<br />
/views/readme.txt
</td>
</tr>
<tr>
<td>
<tt>/views/index??.cfm</tt>
<br />
<tt>_</tt>
</td>
<td>
<em>Matches:</em><br />
/views/index01.cfm<br />
/views/index02.cfm<br />
/views/indexAA.cfm<br />
<br />
<em>Does Not Match:</em><br />
/views/index01.htm<br />
/views/index1.cfm<br />
/views/indexA.cfm<br />
/views/indexOther.cfm<br />
/views/anotherDir/index01.cfm<br />
<br />
<br />
(Remember that `?` matches a single character, so the above example matches only files that start with "index", followed by two wildcard characters and then ".cfm".)
</td>
</tr>
</tbody>
Pattern / Path Separator | Pattern Results |
This method initializes the file pattern matcher and optionally allows you to provide a different path separator (which defaults to /
if not passed) and if you want to the use the listInfo
attribute for internal cfdirectory
calls (typically this is more performant if you do not need information like file size or date last modified).
<!--- Using the default path separator --->
<cfset matcher = CreateObject("component", "MachII.util.matching.FileMatcher").init() />
Argument Name | Required | Default | Description |
---|---|---|---|
pathSeparator | false |
/ |
Allows you to use a different path separator, but default the matcher converts all \ (Windows based file path separators) to / . |
useListInfo | conditional | Defaults to true if your CFML engine supports this behavior | Allows you to indicate if you want to use the listInfo attribute of cfdirectory for faster performance. listInfo does not return file size or date last modified. If you need this information, then set this value to false . |
This method checks if the passed path has a pattern in it by checking to see if the pattern has any *'s or ?'s in it and returns a boolean result.
Example code:
<cfoutput>
Is '/views/index.cfm' a pattern: #matcher.isPattern("/views/index.cfm")#</br>
Is '/views/*.cfm' a pattern: #matcher.isPattern("/views/*.cfm")#
</cfoutput>
Example output:
Is '/views/index.cfm' a pattern: false
Is '/views/*.cfm' a pattern: true
This is the work horse method of this utility and where all the magic happens. This method takes a pattern and a base path to start the search for matching file paths.
Argument Name | Required | Default | Description |
---|---|---|---|
pattern | true |
n/a | The pattern to use for matching. This needs to be a complete absolute path or you can use a relative path from the path argument by starting your pattern with ./
|
path | true |
n/a | The base path directory to run a cfdirectory call against. This path cannot have any patterns in it. |
removeRootPath | false |
n/a | A path to remove from the computed results. This is most useful when looking for .cfm files to be used with cfincludes as those paths cannot be absolute paths. |
excludePatterns | false |
array | An array of patterns to exclude from the final results. This is useful if you want to cast a wide net with your pattern and filter those results further. |
Matching Files with Absolute Path Results
This is most common if you want to match full absolute paths such as images or files on disk. If you wanted to find all .cfm
files to use with cfinclude
, you need to reuse the next method for relative path results.
Example code (find all .png
files starting with the letter a
including all files in nested directories):
<cfset matcher = CreateObject("component", "MachII.util.matching.FileMatcher").init() />
<cfdump var="#matcher.match("./assets/img/**/a*.png", ExpandPath("/MachII/dashboard/"))#"/>
Example output:
As you can see in the dump, we found all the PNG files that start with the letter a
in the Mach-II Dashboard assets. Notice two additional columns in the result:
-
fullPath
- This is the complete absolute path to the file. -
modified
- This is the modified path to the file. This is the same as the full path unless we supplied aremoveRootPath
argument in which themodifiedPath
would be the full path with the remove root path taken off of it.
Matching Files with Relative Path Results
Example code (find all .cfm
files starting with "snip_" including all files in nested directories):
<cfset matcher = CreateObject("component", "MachII.util.matching.FileMatcher").init() />
<cfdump var="#matcher.match("./views/**/snip_*.cfm", ExpandPath("/MachII/dashboard/"), ExpandPath("/MachII"))#"/>
Example output (partial results):
As you can see in the dump, we found all the files that started with "snip_*.cfm" in the Dashboard views. Notice the modifiedPath
has the value from removeRootPath
from it so we can use in cfincludes:
<cfinclude template="/MachII/#somePath#"/>
Extract the path base (the part before the pattern starts) from a string and automatically cleans the path via pathClean(). This method is useful to break a path into a base path part and a pattern part.
Example code:
<cfoutput>
#matcher.extractPathWithoutPattern("c:\some\random\path\**\*.cfm")#</br>
#matcher.extractPathWithoutPattern("/a/mixed\path\of/????/**/*.xml")#
</cfoutput>
Example output:
c:/some/random/path/
/a/mixed/path/of/
This method cleans paths so all paths use a uniform delimiter of /
. This delimiter is safe to use on both Windows and *nix systems.
Example code:
<cfoutput>
#matcher.pathClean("c:\some\random\path\index.cfm")#</br>
#matcher.pathClean("/a/mixed\path\of/items.cfm")#
</cfoutput>
Example output:
c:/some/random/path/index.cfm
/a/mixed/path/of/items.cfm