The Regular Expression Multiline Flag In ColdFusion

Posted October 10, 2006 at 7:41 AM by Ben Nadel

Tags: ColdFusion

I am not sure how this applies directly to ColdFusion regular expressions and the use of REFind() and REReplace(). I have only tested this in the Java regular expressions that are available through ColdFusion (Once you go Java you can't go back). In standard regular expressions, the (^) symbol matches on the beginning of the target string and the ($) symbol matches on the end of the target string. To demonstrate this, let's store some text:

  • <!--- Store some text. --->
  • <cfsavecontent variable="strText">
  • Laughing as he snatched another plate from the stack,
  • Chalked his hands and monstrous back,
  • Said, Boy, stop lying and don't say you've forgotten!
  • Trouble with you is you aint been SQUATTIN!
  • </cfsavecontent>

Now, let's apply a regular expression that matches the entire string (^) to ($):

  • <!--- Match the entire string from start to end. --->
  • <cfset strText = strText.ReplaceAll(
  • "(^[\w\W]+$)",
  • "BEGIN::$1::END"
  • ) />

... we get the following output:

BEGIN::
Laughing as he snatched another plate from the stack,
Chalked his hands and monstrous back,
Said, Boy, stop lying and dont say you've forgotten!
Trouble with you is you aint been SQUATTIN!
::END

Notice that the (^) and ($) did indeed match the start and end of the string. Also, notice that we used a simple expressions [\w\W]+ to match every character in the string. Since \w is the word character and \W is the non-word character, we are definitely going to match every single character that we come across (remember your Ven diagrams).

Now, there is a regular expression flag, (?m), that tells the regular expression to match (^) at the beginning of EVERY line and to match ($) at the end of EVERY line. Let's run the same expression above except this time we will run a multiline flag on it.

  • <!--- Match the multiline string from start to end. --->
  • <cfset strText = strText.ReplaceAll(
  • "(?m)(^[\w\W]+$)",
  • "BEGIN::$1::END"
  • ) />

Notice that we start the expression with the (?m) multiline flag. Running this we get the following output:

BEGIN::
Laughing as he snatched another plate from the stack,
Chalked his hands and monstrous back,
Said, Boy, stop lying and dont say you've forgotten!
Trouble with you is you aint been SQUATTIN!
::END

But wait, isn't that the same exact thing as before? Yes. The problem with our example is that regular expressions are GREEDY. Our regular expression is trying to match as much as possible while still allowing matches on every line. To fix this, we must modify the expression to be non-greedy. To do so, we will add the (?) character after the (+) character:

  • <!---
  • Match the multiline string from start to end. Run
  • this expression as a non-greedy search.
  • --->
  • <cfset strText = strText.ReplaceAll(
  • "(?m)(^[\w\W]+?$)",
  • "BEGIN::$1::END"
  • ) />

This gives us the desired output:

BEGIN::
Laughing as he snatched another plate from the stack,::END
BEGIN::Chalked his hands and monstrous back,::END
BEGIN::Said, Boy, stop lying and don't say you've forgotten!::END
BEGIN::Trouble with you is you aint been SQUATTIN! ::END

Notice that the BEGIN and END strings are inserted at the beginning and the end of every line respectively.

Ok, so that might not look too sexy, but it is very useful. One of the places that I love to use something like this is when I am scripting database calls. Image that I had a delimited list of data in a data file like (we will simulate this in a CFSaveContent tag):

  • <!--- Simulate a delimited data file via CFSaveContent. ---->
  • <cfsavecontent variable="strText">
  • 1,Libby,9.0
  • 2,Anna,7.5
  • 3,Donna,6
  • 4,Sarah,9.5
  • </cfsavecontent>

We can run a multiline regular expression on this that will allow us to create a SQL statement for every line:

  • <!--- Generate SQL scripts. --->
  • <cfset strSQL = strText.ReplaceAll (
  • "(?m)^(\s)*([0-9]+),([^ ]+),([0-9.]+)$",
  • "UPDATE girl SET hotness = $4 WHERE id = $2;"
  • ) />

Here, we are using the (?m) multiline flag. We are also grouping the different data fields. This will give us the output:

UPDATE girl SET hotness = 9.0 WHERE id = 1;
UPDATE girl SET hotness = 7.5 WHERE id = 2;
UPDATE girl SET hotness = 6 WHERE id = 3;
UPDATE girl SET hotness = 9.5 WHERE id = 4;

Dump that in SQL Analyser or a CFQuery tag and we are good to go. Pretty cool huh?

If you are not using regular expressions, learn them. They are really awesome and so freakin' powerful. The multiline flag doesn't come alll that often, but it is great anytime to you want to treat each line as an individual entity. For more control, you can use this with the Java Pattern / Matcher to handle each line on it's own.




Reader Comments

Feb 2, 2007 at 11:09 PM // reply »
172 Comments

Note that anytime, even when using multi-line mode, you should be able to use \A to match the start of the string and \z to match the end. Also note that I haven't tested those operators in ColdFusion, so here's hoping it's not another feature ColdFusion left off the regex support list.


Feb 3, 2007 at 7:53 PM // reply »
11,246 Comments

Just so we're on the same page, is the \A and \z stuff equivalent to ^ and $ when multi-line matching is NOT enabled? And, if I understand what you are saying, then even if you are doing multi-line matching, \A and \z will still match the very beginning / end of the ENTIRE string.

If that is the case, awesome. I was wondering what the heck those were for. I should just learn by now that none of this stuff is excess, that if I don't see the difference between two things, I probably am not understanding it.


Feb 3, 2007 at 9:52 PM // reply »
172 Comments

[If that is the case, awesome.]

That is the case, and it is indeed quite nifty. Another related (but not nearly as useful, IMO) operator is \Z (uppercase z), which matches at the end of the string and never before line breaks, except for the very last line break if the string ends with a line break. (Whoever thought up that operator had too much free time.)


Jan 10, 2008 at 7:01 PM // reply »
172 Comments

Hi again, Ben. I've recently written up a post on the nitty-gritty of the the regex singleline and multiline flags (and why the names can be highly misleading) at http://blog.stevenlevithan.com/archives/singleline-multiline-confusing . Just referencing it here for other people who find this, since I assume you're fairly familiar with how these modes work.


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 23, 2013 at 9:52 PM
Preventing Links In Standalone iPhone Applications From Opening In Mobile Safari
@Muhmmadibn Did you figure out a solution to launching PDFs? I am running into the same issues myself. There is no way to close the PDF or go back once you launch it. Thanks in advance! ... read »
May 23, 2013 at 6:06 PM
The Girl Who Broke My Heart, And Made Me A Better Person
Good day,ladies and gentle men, my name is Dr AMADI the great spell caster in Africa, i have help so many people for different kind of problems,who say there is no solution to problems on earth, that ... read »
May 23, 2013 at 4:26 PM
ColdFusion QueryAppend( qOne, qTwo )
@Heather, Glad people are still getting value out of this! ... read »
May 23, 2013 at 3:49 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@WebManWalking, I meant the code at the bottom (not the video). I did try to experiment with an intermediary variable, like: value = users.id[ i ]; arrayContains( userIDs, value ); ... but t ... read »
May 23, 2013 at 11:06 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Are you talking about As Number: YES As String: YES As Java: YES? If so, that's with 3 different ways of referencing the constant 1, not users.id[1]. Query object references(*) are what seem ... read »
May 23, 2013 at 9:55 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Dan, According to the CF Admin, I'm running Java "1.6.0_45". As far as the DB column, in the database it's an INT. I'll see if I can dig into what CF sees it as. @WebManWalking, But h ... read »
May 23, 2013 at 9:49 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, I think the problem is that we're used to loose typing in ColdFusion, like JavaScript. If a value is a number but it's needed in an expression to be a string, noooo problem. I've encountered ... read »
May 23, 2013 at 9:47 AM
ColdFusion QueryAppend( qOne, qTwo )
You rock! Thank you, thank you, thank you!!! ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools