Cloning RegExp (Regular Expression) Objects In JavaScript
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.
Want to use code from this post? Check out the license.
Reader Comments
Cloning the regular expressions in JavaScript:
```
var regex=/.*/g, clone;
// Easy way
clone=RegExp(regex.source,regex.flags);
// Additional way to add/replace flags
clone=RegExp(regex.source, [].unique.call(regex.flags+'gi').join(''));
console.log(regex, clone);
```