Is there a RegExp.escape function in JavaScript?

Viewed 171442

I just want to create a regular expression out of any possible string.

var usersString = "Hello?!*`~World()[]";
var expression = new RegExp(RegExp.escape(usersString))
var matches = "Hello".match(expression);

Is there a built-in method for that? If not, what do people use? Ruby has RegExp.escape. I don't feel like I'd need to write my own, there have got to be something standard out there.

17 Answers

Another (much safer) approach is to escape all the characters (and not just a few special ones that we currently know) using the unicode escape format \u{code}:

function escapeRegExp(text) {
    return Array.from(text)
           .map(char => `\\u{${char.charCodeAt(0).toString(16)}}`)
           .join('');
}

console.log(escapeRegExp('a.b')); // '\u{61}\u{2e}\u{62}'

Please note that you need to pass the u flag for this method to work:

var expression = new RegExp(escapeRegExp(usersString), 'u');

There is an ES7 proposal for RegExp.escape at https://github.com/benjamingr/RexExp.escape/, with a polyfill available at https://github.com/ljharb/regexp.escape.

An example based on the rejected ES proposal, includes checks if the property already exists, in the case that TC39 backtracks on their decision.


Code:

if (!Object.prototype.hasOwnProperty.call(RegExp, 'escape')) {
  RegExp.escape = function(string) {
    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping
    // https://github.com/benjamingr/RegExp.escape/issues/37
    return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
  };
}

Code Minified:

Object.prototype.hasOwnProperty.call(RegExp,"escape")||(RegExp.escape=function(e){return e.replace(/[.*+\-?^${}()|[\]\\]/g,"\\$&")});

// ...
var assert = require('assert');
 
var str = 'hello. how are you?';
var regex = new RegExp(RegExp.escape(str), 'g');
assert.equal(String(regex), '/hello\. how are you\?/g');

There is also an npm module at: https://www.npmjs.com/package/regexp.escape


One can install this and use it as so:


npm install regexp.escape

or

yarn add regexp.escape

var escape = require('regexp.escape');
var assert = require('assert');
 
var str = 'hello. how are you?';
var regex = new RegExp(escape(str), 'g');
assert.equal(String(regex), '/hello\. how are you\?/g');

In the GitHub && NPM page are descriptions of how to use the shim/polyfill for this option, as well. That logic is based on return RegExp.escape || implementation;, where implementation contains the regexp used above.


The NPM module is an extra dependency, but it also make it easier for an external contributor to identify logical parts added to the code. ¯\(ツ)

There has only ever been and ever will be 12 meta characters that need to be escaped to be considered a literal.

It doesn't matter what is done with the escaped string, inserted into a balanced regex wrapper or appended. It doesn't matter.

Do a string replace using this

var escaped_string = oldstring.replace(/[\\^$.|?*+()[{]/g, '\\$&');

I borrowed bobince's answer above and created a tagged template function for creating a RegExp where part of the value is escaped and part isn't.

regex-escaped.js

RegExp.escape = text => text.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');

RegExp.escaped = flags =>
  function (regexStrings, ...escaped) {
    const source = regexStrings
      .map((s, i) =>
        // escaped[i] will be undefined for the last value of s
        escaped[i] === undefined
          ? s
          : s + RegExp.escape(escaped[i].toString())
      )
      .join('');
    return new RegExp(source, flags);
  };
  
function capitalizeFirstUserInputCaseInsensitiveMatch(text, userInput) {
  const [, before, match, after ] =
    RegExp.escaped('i')`^((?:(?!${userInput}).)*)(${userInput})?(.*)$`.exec(text);

  return `${before}${match.toUpperCase()}${after}`;
}

const text = 'hello (world)';
const userInput = 'lo (wor';
console.log(capitalizeFirstUserInputCaseInsensitiveMatch(text, userInput));

For our TypeScript fans...

global.d.ts

interface RegExpConstructor {
  /** Escapes a string so that it can be used as a literal within a `RegExp`. */
  escape(text: string): string;

  /**
   * Returns a tagged template function that creates `RegExp` with its template values escaped.
   *
   * This can be useful when using a `RegExp` to search with user input.
   *
   * @param flags The flags to apply to the `RegExp`.
   *
   * @example
   *
   * function capitalizeFirstUserInputCaseInsensitiveMatch(text: string, userInput: string) {
   *   const [, before, match, after ] =
   *     RegExp.escaped('i')`^((?:(?!${userInput}).)*)(${userInput})?(.*)$`.exec(text);
   *
   *   return `${before}${match.toUpperCase()}${after}`;
   * }
   */
  escaped(flags?: string): (regexStrings: TemplateStringsArray, ...escapedVals: Array<string | number>) => RegExp;
}

This one is the permanent solution.

function regExpEscapeFuture(literal_string) {
     return literal_string.replace(/[^A-Za-z0-9_]/g, '\\$&');
}
Related