skip to Main Content

How do you clone a regular expression in JavaScript?
I would like to know how to do the following:

  1. Clone the regex itself, not including state properties like lastIndex ("shallow" clone).
  2. Clone the regex object, including state properties like lastIndex ("deep" clone).

2

Answers


  1. Shallow clone the regex itself, not including properties like lastIndex.

    A regular expression consists of a pattern and flags.

    const copy = new RegExp(original.source, original.flags);
    

    Deep clone the regex object, including properties like lastIndex.

    lastIndex is the only state.

    const copy = new RegExp(original.source, original.flags);
    copy.lastIndex = original.lastIndex;
    
    Login or Signup to reply.
  2. The only state used in regular expressions is when the global flag (g) is used that allows for tracking what the last/next match of a regex should be:

    const re = /testd/g;
    const str = "test1 test2";
    
    const res1 = re.exec(str);
    console.log(res1);
    
    const res2 = re.exec(str);
    console.log(res2);

    Clone without state

    To clone the regular expression fully without the state (thus resetting the tracking), you only need to give the regex object to the RegExp constructor which will effectively copy the pattern and flags

    new RegExp(existingRegExp);
    

    Seen in action:

    const re = /testd/g;
    const str = "test1 test2";
    
    const res1 = re.exec(str);
    console.log(res1);
    
    const clonedRegex = cloneWithoutState(re);
    const res2 = clonedRegex.exec(str);
    console.log(res2);
    
    function cloneWithoutState(regex) {
      return new RegExp(regex);
    }

    Note that you can also pass in flags which will override the previous flags:

    const existing = /existing regex/g;
    
    const cloned = new RegExp(existing, "i"); //only set the flags to i - case insensitive
    
    console.log(cloned); // /existing regex/i
    
    const mixCase = "Existing Regex";
    console.log(existing.test(mixCase)); //false
    console.log(cloned.test(mixCase));   //true

    This might be useful to force some flags on, if they are needed, regardless of where the pattern came from.

    Clone with state

    As Ry- points out the only state in an RegExp instance is lastIndex. This can be verified by using Reflect.ownKeys() or Object.getOwnPropertyDescriptors()

    const regex = /regex/;
    
    console.log(Reflect.ownKeys(regex));
    
    console.log(Object.getOwnPropertyDescriptors(regex));

    In order to clone with state, it is enough to copy over the value of the lastIndex key:

    const re = /testd/g;
    const str = "test1 test2";
    
    const res1 = re.exec(str);
    console.log(res1);
    
    const clonedRegex = cloneWithState(re);
    const res2 = clonedRegex.exec(str);
    console.log(res2);
    
    function cloneWithState(regex) {
      const clone = new RegExp(regex);
      clone.lastIndex = regex.lastIndex;
      return clone;
    }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search