RESplit() - Splitting Strings With Regular Expressions In ColdFusion

Posted November 19, 2010 at 10:24 AM by Ben Nadel

Tags: ColdFusion

ColdFusion 8 added the ability for the listToArray() function to include empty fields (rather than just skipping over them). Then, ColdFusion 9 added the ability for the listToArray() function to use multi-character delimiters (rather than using each character as a separate delimiter). This is some great functionality; however, I have a love affair with Regular Expressions and I thought it would be nice to have a splitting function that used patterns rather than static delimiters.

As of ColdFusion 8, we have the reMatch() function. This allows us to extract values that match a given pattern. What I've coded here is reSplit(). This allows us to extract values that exist between matches of a given pattern. In essence, reSplit() lets you view a string as a list in which the value delimiters are regular expression pattern matches.

reSplit( regexPattern, string ) :: Array

The reSplit() functionality builds on top of Java's String::split() method. However, rather than using this as an "undocumented" feature, I am using JavaCast() to ensure that I'm dealing with a valid Java string before any splitting is applied.

  • <cffunction
  • name="reSplit"
  • access="public"
  • returntype="array"
  • output="false"
  • hint="I split the given string using the given Java regular expression.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="regex"
  • type="string"
  • required="true"
  • hint="I am the regular expression being used to split the string."
  • />
  •  
  • <cfargument
  • name="value"
  • type="string"
  • required="true"
  • hint="I am the string being split."
  • />
  •  
  • <!--- Define the local scope. --->
  • <cfset var local = {} />
  •  
  • <!---
  • Get the split functionality from the core Java script. I am
  • using JavaCast here as a way to alleviate the fact that I'm
  • using *undocumented* functionality... sort of.
  •  
  • The -1 argument tells the split() method to include trailing
  • parts that are empty.
  • --->
  • <cfset local.parts = javaCast( "string", arguments.value ).split(
  • javaCast( "string", arguments.regex ),
  • javaCast( "int", -1 )
  • ) />
  •  
  • <!---
  • We now have the individual parts; however, the split()
  • method does not return a ColdFusion array - it returns a
  • typed String[] array. We now have to convert that to a
  • standard ColdFusion array.
  • --->
  • <cfset local.result = [] />
  •  
  • <!--- Loop over the parts and append them to the results. --->
  • <cfloop
  • index="local.part"
  • array="#local.parts#">
  •  
  • <cfset arrayAppend( local.result, local.part ) />
  •  
  • </cfloop>
  •  
  • <!--- Return the result. --->
  • <cfreturn local.result />
  • </cffunction>
  •  
  •  
  •  
  • <!--- ----------------------------------------------------- --->
  • <!--- ----------------------------------------------------- --->
  • <!--- ----------------------------------------------------- --->
  • <!--- ----------------------------------------------------- --->
  •  
  •  
  •  
  • <!--- Create a list of values in which some are empty. --->
  • <cfset womenList = ",Katie,,Jill,Sarah," />
  •  
  • <!--- Split this list, using the comma as our pattern. --->
  • <cfset women = reSplit( ",", womenList ) />
  •  
  • <!--- Output the resultant collection. --->
  • <cfdump
  • var="#women#"
  • label="reSplit() Women"
  • />

As you can see, our value argument is passing through JavaCast() before the .split() method is invoked. This split() method takes a regular expression and returns a typed String array. This typed string array then needs to be converted to a valid ColdFusion array.

When we run the above code, we get the following CFDump output:

 
 
 
 
 
 
RESplit() Uses Regular Expression Pattern Based String Splitting In ColdFusion. 
 
 
 

As you can see, our list was split on the regular expression pattern, ",". This not only split the list, but it maintained the empty values between adjacent delimiters.

NOTE: Because our pattern, in this case, was nothing more than a comma, the same outcome could have been handled with listToArray() and the optional third argument, "includeEmptyFields."

This kind of pattern-based splitting could be great for parsing simple CSV data (ie. data that doesn't have any embedded special characters). Because CSV row delimiters might use the new line, the carriage return, or a combination of the two depending on the originating operating system, we can't really use the listToArray() function. Even with ColdFusion 9's optional argument, "multiCharacterDelimiter," there'd be no way to handle both empty lines as well as the variations in row delimiter.

With pattern-based splitting, however, delimiter variations become much easier:

  • <!--- Define the tab for our field delimiter. --->
  • <cfset tab = chr( 9 ) />
  •  
  • <!--- Define our tab-delimited data. --->
  • <cfsavecontent variable="csvData">
  • <cfoutput>
  • Name#tab#Age#tab#Hair
  • Katie#tab#29#tab#Brown
  • <!--- Totally empty row. --->
  • Jill#tab##tab#Brown
  • #tab##tab#
  • Sarah#tab#33#tab#
  • </cfoutput>
  • </cfsavecontent>
  •  
  •  
  • <!---
  • Remove non-relevant white space - ie. remove the leading or
  • trailing line breaks, but do not remove any TABS.
  • --->
  • <cfset csvData = reReplace(
  • csvData,
  • "^[\r\n]+|[\r\n]+$",
  • "",
  • "all"
  • ) />
  •  
  •  
  • <!--- Get the rows using the line breaks. --->
  • <cfset rows = reSplit( "\r\n?|\n", csvData ) />
  •  
  • <!---
  • Now that we have the rows, loop over them and split each row
  • value by the tab-delimiter. This will result in an array of
  • arrays.
  • --->
  • <cfloop
  • index="rowIndex"
  • from="1"
  • to="#arrayLen( rows )#"
  • step="1">
  •  
  • <!---
  • Convert the row data to an array of field values (as
  • delimited by Tabs).
  • --->
  • <cfset rows[ rowIndex ] = reSplit( tab, rows[ rowIndex ] ) />
  •  
  • </cfloop>
  •  
  • <!--- Output our resultant CSV data. --->
  • <cfdump
  • var="#rows#"
  • label="Parsed CSV Data"
  • />

As you can see, we are splitting the CSV data based on the row-delimiter pattern:

\r\n?|\n

We are then splitting each resultant row on the field-delimiter pattern:

tab

NOTE: Our "tab" here is the variable containing the tab character literal.

When we run this code, we get the following CFDump output:

 
 
 
 
 
 
RESplit() Uses Regular Expression Pattern Based String Splitting Which Can Be Used To Parse CSV Data. 
 
 
 

reMatch() added some awesome extraction functionality in ColdFusion 8; I think that reSplit() would be the prefect complement to that regular expression based parsing.




Reader Comments

Nov 19, 2010 at 10:36 AM // reply »
319 Comments

Any particular reason you would use Java over a completely native CFML one? Ala http://www.cflib.org/udf/resplit

(Holy crap - look at the date that was released!)


Nov 19, 2010 at 10:43 AM // reply »
11,238 Comments

@Ray,

Ha ha, "requires ColdFusion 5" :)

In my experience, I've just found that doing anything with regular expressions is faster when you dip down into the Java layer. Plus, the Java String object already has a split() method, so it just seemed like the easiest approach.


Nov 19, 2010 at 10:45 AM // reply »
319 Comments

Sensible enough to me.


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools