23

In Perl regular expressions, you can surround a subexpression with \Q and \E to indicate that you want that subexpression to be matched as a literal string even if there are metacharacters in there. You also have the quotemeta function that inserts exactly the right number of backslashes in a string so that if you subsequently interpolate that string into a regular expression, it will be matched literally, no matter what its contents were.

Does Javascript (as deployed in major browsers) have any built in equivalent? I can write my own just fine, but I would like to know if I don't have to bother.

Mosty Mostacho
  • 42,742
  • 16
  • 96
  • 123
zwol
  • 135,547
  • 38
  • 252
  • 361

3 Answers3

19

There is no such built-in feature.

Rather than implementing your own, I advise you look into the multitude of regex escape functions available on the internet.

That page proposes the following solution (by Colin Snover):

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

or advises to use the XRegExp library.

Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
Joe Taylor
  • 638
  • 6
  • 12
  • 3
    Thanks. Note to anyone who clicks through the link: read all the way to the bottom for the *correct* version of the routine. – zwol Jun 13 '11 at 17:19
6

Quotemeta isn't implemented natively as far as I know, but I've used this a few months ago for just this:

function quotemeta (str) {
  // http://kevin.vanzonneveld.net
  // +   original by: Paulo Freitas
  // *     example 1: quotemeta(". + * ? ^ ( $ )");
  // *     returns 1: '\. \+ \* \? \^ \( \$ \)'
  return (str + '').replace(/([\.\\\+\*\?\[\^\]\$\(\)])/g, '\\$1');
}

From http://phpjs.org/functions/quotemeta:496

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
Francisc
  • 77,430
  • 63
  • 180
  • 276
2

There's also a quotemeta npm module, which you can use in node.js or in the browser. The implementation is to quote all non-word characters, (short for [^a-zA-Z0-9_]).

String(str).replace(/(\W)/g, '\\$1');

This works because all the characters that need escaping are non-words, while the other characters that end getting escape are harmless. For example, here the percent character gets escaped, but it still matches normally in the RegExp, although it didn't need to be escaped:

if ("Hello%".match(RegExp(String("%").replace(/(\W)/g,'\\$1')))) { console.log("matched!"); } 

```

Someone has forked the quotemeta module and noted that the capturing parens aren't needed, so the regex can be further simplified like this:

String(str).replace(/\W/g, '\\$&');
Mark Stosberg
  • 12,961
  • 6
  • 44
  • 49
  • 2
    Note that this will break surrogate pairs by breaking them apart with a backslash in the middle, corrupting characters like – Jessidhia Nov 17 '16 at 12:11
  • If there's a solution, please submit a PR to the quotemeta module and edit this answer. – Mark Stosberg Nov 17 '16 at 15:33
  • 1
    @Jessidhia, According to my test, it works perfectly fine with surrogate pairs. `{ let s = "\uD800\uDC00"; let re = new RegExp("^" + s.replace(/(\W)/g, '\\$1') + "$"); console.log(re.test(s)); }` – ikegami Nov 10 '20 at 17:47