There have been many times when I needed to simply modify the flags (options) for a regular expression in JavaScript. Unfortunately, the global, ignoreCase, multiline, and sticky (for FireFox) flags are immutable. In addition, when creating a new regular expression from an old one, you can’t supply a regular expression as the first parameter of the constructor followed by a string indicating the desired flags. For this reason, I wrote a definition for a cloning function for regular expressions that provides the ability to supply different flags:

(function(stickySymbol) {
  RegExp.prototype.clone = function(options) {
    // If the options are not in string format...
    if(options + "" !== options) {
      // If the options evaluate to true, use the properties to construct
      // the flags.
      if(options) {
        options = (options.ignoreCase ? "i" : "")
          + (options.global ? "g" : "")
          + (options.multiline ? "m" : "")
          + (options.sticky ? "y" : "");
      }
      // If the options evaluate to false, use the current flags.
      else {
        options = (this + "").replace(/[\s\S]+\//, "");
      }
    }
    
    // Return the new regular expression, making sure to only include the
    // sticky flag if it is available.
    return new RegExp(this.source, options.replace("y", stickySymbol));
  };
})("sticky" in /s/ ? "y" : "");

After the above definition is executed, declarations such as the following can be made:

// regular expression that matches every lowercased vowel
var reLowerCaseVowels = /[aeiou]/g;

// clone of the regular expression that matches every lowercased vowel
var reLowerCaseVowels2 = reLowerCaseVowels.clone();

// regular expressions that match every vowel (case-insensitive),
// specifying the flags via string
var reVowels = reLowerCaseVowels.clone("ig");

// regular expressions that match every vowel (case-insensitive),
// specifying the flags via object literal form
var reVowels2 = reLowerCaseVowels.clone({
  ignoreCase : true,
  global : true
});

2 Comments

ildar · March 11, 2013 at 11:03 AM

Looking for the best solution I bumped into your blog again. I thought that there were better way to clone regexp. But truth is on the side of simple solutions.

1st approach:
r1 = /w+/g;
r2 = eval(r1.toString());

2nd approach:
r1 = /w+/g;
r2 = eval(” + r1);

The first one shows what happens when cloning and the second one is the same as the first one but shorter. Of course, we can say that someone can modify RegExp#toString() method. But we understand overriding methods of embeded objects is wrong and vicious way.

    Chris West · March 12, 2013 at 5:37 PM

    I rarely think of eval as a way to solve a problem. Still, if one isn’t opposed to using eval, the following is a definition of RegExp.prototype.clone which does the same as my other definition but with less code:

    RegExp.prototype.clone = function(flags) {
      var pattern = /(^.+/)(.*)/.exec(this + '');
      return eval(pattern[1] + ((arguments.length ? flags : pattern[2]) || ''));
    }
    

Leave a Reply

Your email address will not be published. Required fields are marked *