Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at cf.Objective() 2011 (Minneapolis, MN) with:

Cloning RegExp (Regular Expression) Objects In JavaScript

By Ben Nadel on

This morning, Mathrick pointed out that the RegExp-cloning approach in my Node.js Transform Streams exploration was fairly inadequate. While it wasn't the focus of the blog post (it was about Node.js streams), he was 100% right - my approach only worked coincidentally with my input. And, as someone who loves regular expressions, I felt like I had to make it right. As such, I've created a more durable cloning function below.

Rather than just calling the .toString() method on the input, I am now checking the incoming RegExp instance for both its source (ie, the pattern) and the individual flags that have been set. Now, in my particular use-case, I also wanted to ensure that the clone had the global ("g") flag set. So, I've created an optional parameter - injectFlags - to allow new flags to be injected into the clone during duplication.

  • <!doctype html>
  • <html>
  • <head>
  • <title>Cloning RegExp (Regular Expression) Objects In JavaScript</title>
  • </head>
  • <body>
  •  
  • <script type="text/javascript">
  •  
  • /**
  • * I clone the given RegExp object, and ensure that the given flags exist on
  • * the clone. The injectFlags parameter is purely additive - it cannot remove
  • * flags that already exist on the
  • *
  • * @input RegExp - I am the regular expression object being cloned.
  • * @injectFlags String( Optional ) - I am the flags to enforce on the clone.
  • */
  • function cloneRegExp( input, injectFlags ) {
  •  
  • var pattern = input.source;
  • var flags = "";
  •  
  • // Make sure the parameter is a defined string - it will make the conditional
  • // logic easier to read.
  • injectFlags = ( injectFlags || "" );
  •  
  • // Test for global.
  • if ( input.global || ( /g/i ).test( injectFlags ) ) {
  •  
  • flags += "g";
  •  
  • }
  •  
  • // Test for ignoreCase.
  • if ( input.ignoreCase || ( /i/i ).test( injectFlags ) ) {
  •  
  • flags += "i";
  •  
  • }
  •  
  • // Test for multiline.
  • if ( input.multiline || ( /m/i ).test( injectFlags ) ) {
  •  
  • flags += "m";
  •  
  • }
  •  
  • // Return a clone with the additive flags.
  • return( new RegExp( pattern, flags ) );
  •  
  • }
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • var regex = new RegExp( "http://www.bennadel.com", "i" );
  •  
  • // Clone the regular expression object, but ensure "g" (global) flag is set
  • // (even if it was not set on the given RegExp instance).
  • var clone = cloneRegExp( regex, "g" );
  •  
  • // The clone should now have both the "i" (source) and "g" (injected) flags set.
  • console.log( "Clone:", clone );
  •  
  • </script>
  • </body>
  • </html>

Notice that the original RegExp object only has the "i" (caseInsensitive) flag being set; but, as I clone it, I'm injected the "g" (global) flag. When I run this code, I get the following console log output:

Clone: RegExp /http:\/\/www.bennadel.com/ig

As you can see, both flags are present on the cloned regular expression object.

I've tested this in Chrome, Firefox, Safari, and whichever version of IE my VirtualBox instance happen to have installed. It appears to work consistently on each.



Reader Comments

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
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.