491

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.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Lance Pollard
  • 66,757
  • 77
  • 237
  • 416
  • 17
    Just wanted to update you fine folk that [`RegExp.escape` is currently worked on](https://github.com/benjamingr/RexExp.escape) and anyone who thinks they have valuable input is very welcome to contribute. core-js and other polyfills offer it. – Benjamin Gruenbaum Jun 14 '15 at 22:48
  • 6
    According to the [recent update of this answer](https://stackoverflow.com/a/9310752/1078886) this proposal was rejected: [See the issue](https://github.com/benjamingr/RegExp.escape/issues/37) – try-catch-finally Jul 19 '17 at 10:15
  • Yeah I believe @BenjaminGruenbaum may be the one who put forward the proposal. I tried to get code examples plus the es-shim npm module into an answer on stack overflow here: [ https://stackoverflow.com/a/63838890/5979634 ] because the proposal was eventually, unfortunately, rejected. Hopefully they change their minds or someone implements 'template tags' before I retire. – Drewry Pope Sep 13 '20 at 10:13

15 Answers15

650

The function linked above is insufficient. It fails to escape ^ or $ (start and end of string), or -, which in a character group is used for ranges.

Use this function:

function escapeRegex(string) {
    return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

While it may seem unnecessary at first glance, escaping - (as well as ^) makes the function suitable for escaping characters to be inserted into a character class as well as the body of the regex.

Escaping / makes the function suitable for escaping characters to be used in a JavaScript regex literal for later evaluation.

As there is no downside to escaping either of them, it makes sense to escape to cover wider use cases.

And yes, it is a disappointing failing that this is not part of standard JavaScript.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
bobince
  • 498,320
  • 101
  • 621
  • 807
  • 4
    @spinningarrow: It represents the whole matched string, like 'group 0' in many other regex systems. [doc](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter) – bobince Aug 08 '12 at 08:11
  • 2
    I believe the original answer was correct, before the edit. I'm pretty sure escaping the forward slash inside the character class is not necessary. It seems to do no harm, but isn't required. – goodeye Feb 13 '13 at 01:31
  • 18
    actually, we don't need to escape `/` at all – thorn0 Feb 14 '13 at 20:53
  • @bobince Is this the expected behaviour: RegExp.escape('a\.b') === 'a\.b', I was expecting 'a\\\.b' (escape "\" and escape ".") ? – Radu Maris Jul 23 '13 at 11:25
  • 1
    @Radu: you have a string literal problem, `'a\.b'`===`'a.b'` :-) – bobince Jul 23 '13 at 11:42
  • 2
    BTW beware of debugger consoles: IE, Firefox and Chrome all display the string `a\.b` in a pseudo-literal form `"a\.b"`, which is misleading as it is not a valid string literal for that value (should be `"a\\.b"`. Thanks for the unnecessary extra confusion, browsers. – bobince Jul 23 '13 at 11:48
  • "it is a disappointing failing that this is not part of standard JavaScript". What languages have something like this? – Paul Draper Oct 03 '13 at 03:26
  • 30
    @Paul: Perl `quotemeta` (`\Q`), Python `re.escape`, PHP `preg_quote`, Ruby `Regexp.quote`... – bobince Oct 03 '13 at 10:24
  • 16
    If you are going to use this function in a loop, it's probably best to make the RegExp object it's own variable `var e = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;` and then your function is `return s.replace(e, '\\$&');` This way you only instantiate the RegExp once. – styfle Oct 17 '13 at 21:14
  • 3
    You don't need to escape '-'. When you escape '[', the '-' is not inside a character class, and it has no special meaning. The '/' isn't necessary either. – lrn Feb 20 '14 at 12:01
  • Hi, can this be extended to also escape the double quote character (")? – Shaggydog Jun 12 '14 at 08:33
  • 2
    @Shaggydog: it certainly could be, but I can't think of a place where `"` is special in regex syntax so I'm not sure what the benefit would be. – bobince Jun 12 '14 at 10:09
  • 2
    @Shaggydog: you're talking about JavaScript string literal escaping. That's a different thing to regex escaping. They both use backslashes but otherwise the rules are quite different. (If you have a string in a regex *inside* a string literal then you would have to use both types of escaping, one after another.) – bobince Jun 12 '14 at 16:12
  • 17
    Standard arguments against augmenting built-in objects apply here, no? What happens if a future version of ECMAScript provides a `RegExp.escape` whose implementation differs from yours? Wouldn't it be better for this function not to be attached to anything? – Mark Amery Feb 23 '15 at 17:16
  • Actually you are not required to escape the `/` in character classes, though it's better to escape it to accommodate some editors. See this [question](http://stackoverflow.com/questions/9226731/escape-forward-slash-in-jscript-regexp-character-class). – Gras Double Sep 06 '15 at 04:34
  • This is not working for decimal points. `RegExp("1.3")` returning `/1.3/` which is totally unacceptable. Pi Marillion's answer below is working fine when fed with numbers that contain decimal points. – Redu Mar 24 '16 at 12:15
  • 2
    @Redu: ??? you appear to have called the `RegExp` constructor instead of `Regexp.escape`... – bobince Mar 26 '16 at 16:34
  • 2
    In a 'hostile' generic function, you probably want to consider protecting yourself from javascript typing by doing `String(s).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');` This helps when your string is a number, for example. – Paul Cuddihy Aug 01 '16 at 19:55
  • "As there is no downside to escaping either of them... " Reduced readability. – ChrisJJ Dec 09 '16 at 16:12
  • 2
    ESLint throws an error with this RegExp by default (`no-useless-escape`): Unnecessary escape character: \/ – dude Sep 15 '17 at 08:08
  • 25
    bobince cares not for eslint's opinion – bobince Sep 15 '17 at 22:57
  • 1
    The expression can be reduced to this: `/[$(-+.\/?[-^{|}]/` (saves 5 characters). You don't need to escape `-` because you already escaped `[` and `]` and that means there won't be character groups. Also, there are two character sequences that can be written as ranges. One between `(` and `+` (40 through 43) and another between `[` and `^` (91 through 94). – JP de la Torre Oct 06 '17 at 19:06
  • 6
    But maybe you want to escape characters to put them *inside* a character range. IMO better to harmlessly overescape than to underescape and cause problems in niche cases. FWIW personally I'd rather see the characters explicitly here; we're not playing code golf. – bobince Oct 12 '17 at 20:54
  • why are not included the [double]quotes itself, I mean converting `"` to `\"` and `'` to `\'`? `str.replace(/[\-\[\]\/\{\}\(\)\"\'\*\+\?\.\\\^\$\|]/g, "\\$&");` – João Pimentel Ferreira Jan 21 '18 at 21:48
  • 1
    @JoãoPimentelFerreira well, quotes have no special meaning to regex (see Shaggydog's comment above). – bobince Jan 29 '18 at 22:19
  • @bobince for me escaping quotes is important if you use this function for example as a `handlebarsjs` helper or any other rendering engine, for example if I use `handlebarsjs` to render a JS file where I have `var JSstr = '{{{myStr}}}';` where `myStr = "I'm here"`. If I don't escape the quotes I get `var JSstr = 'I'm here'`. But I am aware that this is a very particular and specific situation. – João Pimentel Ferreira Jan 29 '18 at 23:09
  • 4
    @JoãoPimentelFerreira that's not regex escaping, that's JavaScript string literal escaping. The rules for these syntaxes are different and not compatible; applying a regex escaper to `myStr` would not make the result correct even if quotes were escaped. If you are writing a string into a regex *inside* a string literal, you would need to regex-escape it first, and then string-literal-escape the results (so eg a backslash ends up as a quadruple-backslash). – bobince Feb 01 '18 at 21:18
  • 5
    Because getting nested escaping right is tricky, and the outcome of getting it wrong is so severe (cross-site-scripting vulns), it's generally a bad idea to inject data into JavaScript code. You are generally better off writing content into a data attribute (eg ``, using handlebars's normal HTML-escaping), and then reading the content of that attribute from static JS. – bobince Feb 01 '18 at 21:20
  • @bobince just a short question: how can be a bad idea to inject data into Javascript with handlebars if everything is made server-side, for example inline with the – João Pimentel Ferreira Feb 01 '18 at 21:42
  • 2
    @JoãoPimentelFerreira if any of the data you're injecting comes from outside the application, then whoever is supplying the data can cause code of their own choosing to run on the browsers of anyone else using the application's output, allowing them to do anything that user can do on your site. This is Cross-Site Scripting and it's one of the worst, most widespread security issues on the web today. – bobince Feb 01 '18 at 21:49
  • 5
    And the disappoint continues, [either years and lots of other improvements later](https://esdiscuss.org/topic/regexp-escape)... – T.J. Crowder Aug 28 '18 at 17:21
  • I have a `string.replaceAll(haystack, needle, replace)` function. It calls `haystack.replace( new RegExp( escape(needle), 'g' ), replace);` but I just found an edge case where it breaks: 'string as a parameter', so if the `replace` param contains, for example, `$'` my function returns weird results. Any idea how to fix this? See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter – REJH Aug 02 '19 at 19:22
135

For anyone using Lodash, since v3.0.0 a _.escapeRegExp function is built-in:

_.escapeRegExp('[lodash](https://lodash.com/)');
// → '\[lodash\]\(https:\/\/lodash\.com\/\)'

And, in the event that you don't want to require the full Lodash library, you may require just that function!

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
gustavohenke
  • 38,209
  • 13
  • 113
  • 120
  • 6
    there's even an npm package of just this! https://www.npmjs.com/package/lodash.escaperegexp – Ted Pennings Nov 01 '15 at 07:34
  • Be aware that the escapeRegExp function lodash also adds **\x3** to the beginning of the string, not really sure why. – maddob Jul 28 '16 at 12:39
  • 1
    This imports loads of code that really doesn't need to be there for such a simple thing. Use bobince's answer... works for me and its so many less bytes to load than the lodash version! – Rob Evans Aug 31 '17 at 13:20
  • 7
    @RobEvans my answer starts with _"For anyone using lodash"_, and I even mention that you can require *only* the `escapeRegExp` function. – gustavohenke Aug 31 '17 at 13:24
  • 2
    @gustavohenke Sorry I should have been slightly more clear, I included the module linked to in your "just that function" and that is what I was commenting on. If you take a look it's quite a lot of code for what should effectively be a single function with a single regexp in it. Agree if you are already using lodash then it makes sense to use it, but otherwise use the other answer. Sorry for the unclear comment. – Rob Evans Aug 31 '17 at 18:03
  • 2
    @maddob I cannot see that \x3 you mentioned: my escaped strings are looking good, just what I expect – Federico Fissore May 31 '18 at 15:10
47

Most of the expressions here solve single specific use cases.

That's okay, but I prefer an "always works" approach.

function regExpEscape(literal_string) {
    return literal_string.replace(/[-[\]{}()*+!<=:?.\/\\^$|#\s,]/g, '\\$&');
}

This will "fully escape" a literal string for any of the following uses in regular expressions:

  • Insertion in a regular expression. E.g. new RegExp(regExpEscape(str))
  • Insertion in a character class. E.g. new RegExp('[' + regExpEscape(str) + ']')
  • Insertion in integer count specifier. E.g. new RegExp('x{1,' + regExpEscape(str) + '}')
  • Execution in non-JavaScript regular expression engines.

Special Characters Covered:

  • -: Creates a character range in a character class.
  • [ / ]: Starts / ends a character class.
  • { / }: Starts / ends a numeration specifier.
  • ( / ): Starts / ends a group.
  • * / + / ?: Specifies repetition type.
  • .: Matches any character.
  • \: Escapes characters, and starts entities.
  • ^: Specifies start of matching zone, and negates matching in a character class.
  • $: Specifies end of matching zone.
  • |: Specifies alternation.
  • #: Specifies comment in free spacing mode.
  • \s: Ignored in free spacing mode.
  • ,: Separates values in numeration specifier.
  • /: Starts or ends expression.
  • :: Completes special group types, and part of Perl-style character classes.
  • !: Negates zero-width group.
  • < / =: Part of zero-width group specifications.

Notes:

  • / is not strictly necessary in any flavor of regular expression. However, it protects in case someone (shudder) does eval("/" + pattern + "/");.
  • , ensures that if the string is meant to be an integer in the numerical specifier, it will properly cause a RegExp compiling error instead of silently compiling wrong.
  • #, and \s do not need to be escaped in JavaScript, but do in many other flavors. They are escaped here in case the regular expression will later be passed to another program.

If you also need to future-proof the regular expression against potential additions to the JavaScript regex engine capabilities, I recommend using the more paranoid:

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

This function escapes every character except those explicitly guaranteed not be used for syntax in future regular expression flavors.


For the truly sanitation-keen, consider this edge case:

var s = '';
new RegExp('(choice1|choice2|' + regExpEscape(s) + ')');

This should compile fine in JavaScript, but will not in some other flavors. If intending to pass to another flavor, the null case of s === '' should be independently checked, like so:

var s = '';
new RegExp('(choice1|choice2' + (s ? '|' + regExpEscape(s) : '') + ')');
Gras Double
  • 14,028
  • 7
  • 52
  • 50
Pi Marillion
  • 3,421
  • 16
  • 17
  • 1
    The `/` doesn't need to be escaped in the `[...]` character class. – Dan Dascalescu Jul 04 '17 at 11:32
  • 1
    Most of these doesn't need to be escaped. _"Creates a character range in a character class"_ - you are never in a character class inside of the string. _"Specifies comment in free spacing mode, Ignored in free spacing mode"_ - not supported in javascript. _"Separates values in numeration specifier"_ - you are never in numerarion specifier inside of the string. Also you can't write arbitrary text inside of nameration specification. _"Starts or ends expression"_ - no need to escape. Eval is not a case, as it would require much more escaping. [will be continued in the next comment] – Qwertiy Sep 22 '17 at 14:01
  • _"Completes special group types, and part of Perl-style character classes"_ - seems not available in javascript. _"Negates zero-width group, Part of zero-width group specifications"_ - you never have groups inside of the string. – Qwertiy Sep 22 '17 at 14:01
  • @Qwertiy The reason for these extra escapes is to eliminate edge cases which could cause problems in certain use cases. For instance, the user of this function may want to insert the escaped regex string into another regex as part of a group, or even for use in another language besides Javascript. The function does not make assumptions like "I will never be part of a character class", because it's meant to be _general_. For a more YAGNI approach, see any of the other answers here. – Pi Marillion Sep 22 '17 at 20:14
  • Very good. Why is _ not escaped though? What ensures it probably won't become regex syntax later? – madprops Oct 29 '17 at 11:43
  • @PiMarillion: In the comments to bobince's answer the user styfle suggested for use in a loop to first create a RegExp-object of the escape-string: `var e = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;` and then the function is like `return s.replace(e, '\\$&');`. To avoid manually escaping the escape string I want first to use the original function `regExpEscape` to escape your escape string (ees), then use `e = new RegExp(ees,"g")` and then `function regExpEscapeFast(literal_string) { return literal_string.replace(e, '\\$&');}`. I can't get it working. How to correctly escape the escape string? – John Dec 07 '17 at 03:23
  • you saved me bruh! – Barbz_YHOOL Mar 09 '21 at 18:58
36

Mozilla Developer Network's Guide to Regular Expressions provides this escaping function:

function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
Lonnie Best
  • 6,765
  • 9
  • 44
  • 81
quietmint
  • 12,585
  • 6
  • 44
  • 69
22

In jQuery UI's autocomplete widget (version 1.9.1) they use a slightly different regular expression (line 6753), here's the regular expression combined with bobince's approach.

RegExp.escape = function( value ) {
     return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Pierluc SS
  • 2,958
  • 7
  • 29
  • 43
  • 4
    The only difference is that they escape `,` (which is not a metacharacter), and `#` and whitespace which only matter in free-spacing mode (which is not supported by JavaScript). However, they do get it right not to escape the the forward slash. – Martin Ender Jul 08 '13 at 10:22
  • 19
    If you want to reuse jquery UI's implementation rather than paste the code locally, go with `$.ui.autocomplete.escapeRegex(myString)`. – Scott Stafford Aug 19 '13 at 18:37
  • 2
    lodash has this too, _. escapeRegExp and https://www.npmjs.com/package/lodash.escaperegexp – Ted Pennings Nov 01 '15 at 07:35
  • v1.12 the same, ok! – Peter Krauss Mar 07 '17 at 03:27
14

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.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
  • 11
    Looks like this [didn't make it into ES7](https://github.com/tc39/proposals/blob/master/finished-proposals.md). It also looks like it was [rejected in favor of looking for a template tag](https://github.com/tc39/proposals/blob/master/inactive-proposals.md). – John Apr 29 '17 at 07:30
  • 1
    @John yeah this looks like the case, at which point the entire concept has been abandoned for at least 5 years. I've added an example here, as it probably should have been implemented and TC39 still hasn't implemented their 'tag' based solution. This seems more in-line with getting what you expect, although I could also see it as a String.prototype method. At some point they should reconsider and implement this, even if they get around to parameterized regex. Most other languages impl escape though, even if they have parameterized queries, so we'll see. – Drewry Pope Sep 07 '20 at 16:00
  • I have added code examples based on this proposal. Thank you for adding this answer that led me to the proposal. I attempted to edit this answer to add exact examples, but this was rejected by the mods. Here is the answer with code examples: [ https://stackoverflow.com/a/63838890/5979634 ] – Drewry Pope Sep 13 '20 at 10:11
13

Nothing should prevent you from just escaping every non-alphanumeric character:

usersString.replace(/(?=\W)/g, '\\');

You lose a certain degree of readability when doing re.toString() but you win a great deal of simplicity (and security).

According to ECMA-262, on the one hand, regular expression "syntax characters" are always non-alphanumeric, such that the result is secure, and special escape sequences (\d, \w, \n) are always alphanumeric such that no false control escapes will be produced.

filip
  • 3,002
  • 1
  • 24
  • 22
  • 1
    Simple and effective. I like this much better than the accepted answer. For (really) old browsers, `.replace(/[^\w]/g, '\\$&')` would work in the same way. – Tomas Langkaas Aug 10 '17 at 07:20
  • 6
    This fails in Unicode mode. For example, `new RegExp(''.replace(/(?=\W)/g, '\\'), 'u')` throws exception because `\W` matches each code unit of a surrogate pair separately, resulting in invalid escape codes. – Alexey Lebedev Feb 02 '18 at 10:29
  • 1
    alternative: `.replace(/\W/g, "\\$&");` – Miguel Pynto Mar 21 '18 at 14:34
  • @AlexeyLebedev Hes the answer been fixed to handle Unicode mode? Or is there a solution elsewhere which does, while maintaining this simplicity? – johny why Apr 26 '20 at 21:07
5

This is a shorter version.

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

This includes the non-meta characters of %, &, ', and ,, but the JavaScript RegExp specification allows this.

kzh
  • 17,642
  • 10
  • 68
  • 95
  • 2
    I wouldn't use this "shorter" version, since the character ranges hide the list of characters, which makes it harder to verify the correctness at first glance. – nhahtdh Nov 27 '14 at 03:03
  • @nhahtdh I probably wouldn't either, but it is posted here for information. – kzh Nov 27 '14 at 12:15
  • @kzh: posting "for information" helps less than posting for understanding. Would you not agree that [my answer](http://stackoverflow.com/a/25090658/1269037) is clearer? – Dan Dascalescu Nov 27 '14 at 21:14
  • At least, `.` is missed. And `()`. Or not? `[-^` is strange. I don't remember what is there. – Qwertiy Sep 22 '17 at 20:35
  • Those are in the specified range. – kzh Sep 22 '17 at 21:15
  • @nhahtdh Why must this "readable"? We're talking regex, the most unreadable code in tarnation. It takes an hour, a magnifying glass, and constant reference to a manual to analyse any complex regex pattern I think "readability" is NOT a priority when it comes to regex. Escape a complex string containing many reserved chars, and the result will be even more unreadable. If you know how to analyze regex that well, then the range-style used here should not be a problem for you. If you DON'T analyze regex that well, then the full list of chars isn't going to help you much anyway. – johny why Apr 26 '20 at 21:01
  • @johnywhy I analyze regex well, but I don't have the whole ASCII table or Unicode code points in my head. Ranges are easy to read when it's something natural, like `a-z` or `0-9` or denotes a range with explicit code points like `\u0000-\u001f`. It's hard to read when you write `[!-|]` (for example), which unless you refer to an ASCII table, you wouldn't know that it covers upper and lower case character. `\u0021-\u007c` may not tell you exactly what characters, but it shows you how many characters there are in the range, then you can proceed to investigate what is in the range – nhahtdh Apr 27 '20 at 09:06
  • @nhahtdh i don't have most/any regex syntax in my head, so i'll be referring to helpdocs with any regex code. If i want to analyze , i'll open up an ascii table. Big deal. As long as the ascii table isn't going to change, i'm comfortable with brevity. – johny why Apr 27 '20 at 11:37
4

XRegExp has an escape function:

XRegExp.escape('Escaped? <.>'); // -> 'Escaped\?\ <\.>'

More on: http://xregexp.com/api/#escape

Antoine Dusséaux
  • 3,060
  • 1
  • 19
  • 28
4

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');
soheilpro
  • 856
  • 10
  • 19
4

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. ¯\(ツ)

Drewry Pope
  • 128
  • 1
  • 9
  • 1
    This answer begins identically to [ https://stackoverflow.com/a/30852428/5979634 ], I had hoped to edit their answer to include this information, but a simpler version of this was considered too different from the original answer. I figured I offered actual code examples within the website, but I'm not gonna argue. Instead, I've offered this as a new, expanded answer, seeing as it is too different from the one other answer like this. – Drewry Pope Sep 13 '20 at 10:09
3
escapeRegExp = function(str) {
  if (str == null) return '';
  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};
pzaenger
  • 7,620
  • 2
  • 31
  • 39
Ravi Gadhia
  • 300
  • 2
  • 8
3

Rather than only escaping characters which will cause issues in your regular expression (e.g.: a blacklist), consider using a whitelist instead. This way each character is considered tainted unless it matches.

For this example, assume the following expression:

RegExp.escape('be || ! be');

This whitelists letters, number and spaces:

RegExp.escape = function (string) {
    return string.replace(/([^\w\d\s])/gi, '\\$1');
}

Returns:

"be \|\| \! be"

This may escape characters which do not need to be escaped, but this doesn't hinder your expression (maybe some minor time penalties - but it's worth it for safety).

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
bashaus
  • 1,402
  • 1
  • 14
  • 27
1

The functions in the other answers are overkill for escaping entire regular expressions (they may be useful for escaping parts of regular expressions that will later be concatenated into bigger regexps).

If you escape an entire regexp and are done with it, quoting the metacharacters that are either standalone (., ?, +, *, ^, $, |, \) or start something ((, [, {) is all you need:

String.prototype.regexEscape = function regexEscape() {
  return this.replace(/[.?+*^$|({[\\]/g, '\\$&');
};

And yes, it's disappointing that JavaScript doesn't have a function like this built-in.

Dan Dascalescu
  • 110,650
  • 40
  • 276
  • 363
  • 1
    Let's say you escape the user input `(text)next` and insert it in: `(?:` + input + `)`. Your method will give the resulting string `(?:\(text)next)` which fails to compile. Note that this is quite a reasonable insertion, not some crazy one like ``re\`` + input + `re` (in this case, the programmer can be blamed for doing something stupid) – nhahtdh Nov 27 '14 at 02:58
  • 1
    @nhahtdh: my answer specifically mentioned escaping entire regular expressions and "being done" with them, not parts (or future parts) of regexps. Kindly undo the downvote? – Dan Dascalescu Nov 27 '14 at 21:08
  • 1
    It's rarely the case that you would escape the entire expression - there are string operation, which are much faster compared to regex if you want to work with literal string. – nhahtdh Nov 28 '14 at 01:24
  • This is not mentioning that it is incorrect - ``\`` should be escaped, since your regex will leave `\w` intact. Also, JavaScript doesn't seem to allow trailing `)`, at least that is what Firefox throws error for. – nhahtdh Nov 28 '14 at 01:30
  • I have escaped `\`` in the answer. Thanks! – Dan Dascalescu Nov 28 '14 at 01:33
  • 2
    Please address the part about closing `)` – nhahtdh Nov 28 '14 at 04:22
  • 1
    It would be right to escape closing braces too, even if they are allowed by some dialect. As I remember, that's an extension, not a rule. – Qwertiy Sep 22 '17 at 20:34
1

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, '\\$&');
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123