So the question I recently raised with myself was how would I go about looping over the contents of a file line by line using Coldfusion scripting? Well it turns out that it’s not too difficult although I did run into a small snag. First let’s look at how to loop over the lines in a file using cfscript. What I’m going to do is try to locate any ‘<cfinclude’ tags in the file being looped over and return the results.
Looping over lines
var loc_delimiter = chr(10);
var loc_numOfLines = listLen(arguments.fileData, loc_delimiter);
for(var i = 1; i <= loc_numOfLines; i = i + 1)
{
loc_matches = {};
loc_thisLine = listGetAt(arguments.fileData, i, loc_delimiter);
loc_matches.line = i;
loc_matches.matches = reMatchNoCase("<cfinclude", loc_thisLine);
if(!arrayIsEmpty(loc_matches.matches))
{
arrayAppend(loc_allMatches, loc_matches);
}
}
This assumes that file data has been read into memory using fileRead().
So our delimiter is chr(10) which means look for a new line feed. You can also use this in conjunction with the ‘return’ chr(13) to be safe. The key is to turn the file into a list delimited by the new line character and/or the carriage return character (these are the hidden characters you may have seen show up in your Word document by accidentally pressing some unknown key combination). Once we have a list we can loop through the length. For each loop we want to use the listGetAt() function to get the data on that line. Essentially and index is equal to a line in this context. We can then use a regular expression to look for any ‘<cfinclude’ matches and append them to an array if we find one.
That was easy! But not quite. Something I noticed when performing this method was that any blank line would get skipped. It wouldn’t get it’s very own index in the list because it quite literally contained nothing. It’s kind of hard to assign the value of nothing to a list. This is kind of like adding 0 to 5. You can do it all night, but it will always continue to equal 5. As such, my file may have actually had 30 lines, but because 5 of those lines were blank the Coldfusion loop would only think there were 25 lines.
To solve this issue I only needed to give some type of value to the empty line before looping over the file contents. I chose to add a chr(32) (what happens behind the scenes when you hit the space bar) just before each new line. To accomplish this I simply used a replaceNoCase() function that replaced all chr(10) with chr(32) & chr(10). This way I still have my new lines, which are my delimiters, but I also make sure all lines have some type of data so each line gets counted.
A final private function that performs this evaluation on any file passed in would look like the following.
A final function
private array function evaluateData(required string fileData)
{
var loc_data = structNew();
var loc_delimiter = chr(10);
var loc_thisLine = "";
var loc_allMatches = [];
var loc_numOfLines = 0;
var loc_matches = {};
//add a space chr(32) to each new line feed so that it picks up blank lines as well
arguments.fileData = replaceNoCase(arguments.fileData, chr(10), chr(32) & chr(10), "all");
loc_numOfLines = listLen(arguments.fileData, loc_delimiter);
for(var i = 1; i <= loc_numOfLines; i = i + 1)
{
loc_matches = {};
loc_thisLine = listGetAt(arguments.fileData, i, loc_delimiter);
loc_matches.line = i;
loc_matches.matches = reMatchNoCase("<cfinclude", loc_thisLine);
if(!arrayIsEmpty(loc_matches.matches))
{
arrayAppend(loc_allMatches, loc_matches);
}
}
return loc_allMatches;
}
Um – why not use fileReadLine()?
Well, that sounds easy
I simply didn’t know about this function. Thanks for sharing a much simpler way!