<!--- Save CSV data values. Here, we are creating a CSV data value that has both qualified and non-qualified field values, populated and empty field values, and embedded field qualifiers and field/line delimiters. ---> <cfsavecontent variable="strCSV"> "Name","Nick Name","Age","Hair Color" Kim,"Kim ""Hot Legs"" Smith",24,"Brunette" "Sarah Vivenz, II","Stubs",27,"Brunette" "Kit Williams",Kitty,34,Blonde,,, "Even Values With Embedded Line Breaks" </cfsavecontent> <!--- Trim data values. ---> <cfset strCSV = Trim( strCSV ) /> <!--- Get the regular expression to match the tokens. I have put the field value on the first line and delimiters on the second line for easier reading. ---> <cfset strRegEx = ( "(""(?:[^""]|"""")*""|[^"",\r\n]*)" & "(,|\r\n?|\n)?" )/> <!--- Create a compiled Java regular expression pattern object based on the pattern above. ---> <cfset objPattern = CreateObject( "java", "java.util.regex.Pattern" ).Compile( JavaCast( "string", strRegEx ) ) /> <!--- Get the pattern matcher for our target text (the CSV data). This will allows us to iterate over all the data fields. ---> <cfset objMatcher = objPattern.Matcher( JavaCast( "string", strCSV ) ) /> <!--- Create an array to hold the CSV data. We are going to create an array of arrays in which each nested array represents a row in the CSV data file. ---> <cfset arrData = ArrayNew( 1 ) /> <!--- Start off with a new array for the new data. ---> <cfset ArrayAppend( arrData, ArrayNew( 1 ) ) /> <!--- Here's where the magic is taking place; we are going to use the Java pattern matcher to iterate over each of the CSV data fields using the regular expression we defined above. Each match will have at least the field value and possibly an optional trailing delimiter. ---> <cfloop condition="objMatcher.Find()"> <!--- Get the field token value. ---> <cfset REQUEST.Value = objMatcher.Group( JavaCast( "int", 1 ) ) /> <!--- Remove the field qualifiers (if any). ---> <cfset REQUEST.Value = REQUEST.Value.ReplaceAll( JavaCast( "string", "^""|""$" ), JavaCast( "string", "" ) ) /> <!--- Unesacepe embedded qualifiers (if any). ---> <cfset REQUEST.Value = REQUEST.Value.ReplaceAll( JavaCast( "string", "(""){2}" ), JavaCast( "string", "$1" ) ) /> <!--- Add the field value to the row array. ---> <cfset ArrayAppend( arrData[ ArrayLen( arrData ) ], REQUEST.Value ) /> <!--- Get the delimiter. If no delimiter group was matched, this will destroy the variable in the REQUEST scope. ---> <cfset REQUEST.Delimiter = objMatcher.Group( JavaCast( "int", 2 ) ) /> <!--- Check for delimiter. ---> <cfif StructKeyExists( REQUEST, "Delimiter" )> <!--- Check to see if we need to start a new array to hold the next row of data. We need to do this if the delimiter we just found is NOT a field delimiter. ---> <cfif (REQUEST.Delimiter NEQ ",")> <!--- Start new row data array. ---> <cfset ArrayAppend( arrData, ArrayNew( 1 ) ) /> </cfif> <cfelse> <!--- If there is no delimiter, then we are done parsing the CSV file data. Break out rather than just ending the loop to make sure we don't get any extra data. ---> <cfbreak /> </cfif> </cfloop> <!--- Dump out CSV data array. ---> <cfdump var="#arrData#" label="CSV File Data" />