Is there a RegExp.escape function in JavaScript?
Asked Answered
P

20

621

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.

Plumule answered 24/8, 2010 at 22:22 Comment(5)
Just wanted to update you fine folk that RegExp.escape is currently worked on and anyone who thinks they have valuable input is very welcome to contribute. core-js and other polyfills offer it.Esmeralda
According to the recent update of this answer this proposal was rejected: See the issueMacedoine
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://mcmap.net/q/21318/-is-there-a-regexp-escape-function-in-javascript ] because the proposal was eventually, unfortunately, rejected. Hopefully they change their minds or someone implements 'template tags' before I retire.Thegn
The aforementioned proposal has just advanced to stage 2Darlinedarling
2023 is coming to the end but most popular string-focused language doesn't have built in for the regexp escape. This never stops amuse me.Assertion
F
803

The function linked in another answer 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.

Fanfaronade answered 24/8, 2010 at 23:9 Comment(31)
@spinningarrow: It represents the whole matched string, like 'group 0' in many other regex systems. docFanfaronade
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.Threemaster
actually, we don't need to escape / at allBeanie
@Fanfaronade Is this the expected behaviour: RegExp.escape('a\.b') === 'a\.b', I was expecting 'a\\\.b' (escape "\" and escape ".") ?Rodas
@Radu: you have a string literal problem, 'a\.b'==='a.b' :-)Fanfaronade
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.Fanfaronade
"it is a disappointing failing that this is not part of standard JavaScript". What languages have something like this?Karrikarrie
@Paul: Perl quotemeta (\Q), Python re.escape, PHP preg_quote, Ruby Regexp.quote...Fanfaronade
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.Verniavernice
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.Bischoff
Hi, can this be extended to also escape the double quote character (")?Lubber
@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.Fanfaronade
@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.)Fanfaronade
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.Teresiateresina
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.Condyle
@Redu: ??? you appear to have called the RegExp constructor instead of Regexp.escape...Fanfaronade
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.Procession
"As there is no downside to escaping either of them... " Reduced readability.Overdrive
ESLint throws an error with this RegExp by default (no-useless-escape): Unnecessary escape character: \/Sabinasabine
bobince cares not for eslint's opinionFanfaronade
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).Ramekin
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.Fanfaronade
why are not included the [double]quotes itself, I mean converting " to \" and ' to \'? str.replace(/[\-\[\]\/\{\}\(\)\"\'\*\+\?\.\\\^\$\|]/g, "\\$&");Anadromous
@JoãoPimentelFerreira well, quotes have no special meaning to regex (see Shaggydog's comment above).Fanfaronade
@Fanfaronade 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.Anadromous
@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).Fanfaronade
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 <html data-jsstr="{{myStr}}">, using handlebars's normal HTML-escaping), and then reading the content of that attribute from static JS.Fanfaronade
@Fanfaronade 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 <script> tag inside the html?Anadromous
@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.Fanfaronade
And the disappoint continues, either years and lots of other improvements later...Boilermaker
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 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Uncinate
A
194

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!

Antiseptic answered 17/4, 2015 at 13:14 Comment(6)
there's even an npm package of just this! npmjs.com/package/lodash.escaperegexpSudorific
Be aware that the escapeRegExp function lodash also adds \x3 to the beginning of the string, not really sure why.Afrit
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!Blackdamp
@RobEvans my answer starts with "For anyone using lodash", and I even mention that you can require only the escapeRegExp function.Antiseptic
@Antiseptic 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.Blackdamp
@Afrit I cannot see that \x3 you mentioned: my escaped strings are looking good, just what I expectReprint
E
56

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) : '') + ')');
Execratory answered 15/6, 2015 at 17:9 Comment(8)
The / doesn't need to be escaped in the [...] character class.Enriquetaenriquez
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]Woolly
"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.Woolly
@Woolly 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.Execratory
Very good. Why is _ not escaped though? What ensures it probably won't become regex syntax later?Reames
@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?Rubidium
you saved me bruh!Plated
If you escape the extra characters, the regular expression will not work with the u flag. For example, /\#/u.test('#') does not compile. See my article: abareplace.com/blog/escape-regexpGonfalon
L
49

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

function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
Lilas answered 13/5, 2014 at 17:22 Comment(0)
C
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, "\\$&");
}
Carbide answered 31/10, 2012 at 12:30 Comment(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.Terresaterrestrial
If you want to reuse jquery UI's implementation rather than paste the code locally, go with $.ui.autocomplete.escapeRegex(myString).Marvelofperu
lodash has this too, _. escapeRegExp and npmjs.com/package/lodash.escaperegexpSudorific
v1.12 the same, ok!Checked
T
17

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.

Treadmill answered 15/6, 2015 at 18:29 Comment(3)
Looks like this didn't make it into ES7. It also looks like it was rejected in favor of looking for a template tag.Rubidium
@Rubidium 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.Thegn
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://mcmap.net/q/21318/-is-there-a-regexp-escape-function-in-javascript ]Thegn
K
15

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.

Kainite answered 12/11, 2016 at 11:35 Comment(4)
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.Chemar
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.Buehrer
alternative: .replace(/\W/g, "\\$&");Pannier
@AlexeyLebedev Hes the answer been fixed to handle Unicode mode? Or is there a solution elsewhere which does, while maintaining this simplicity?Bedbug
T
12

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

Thegn answered 10/9, 2020 at 23:26 Comment(1)
This answer begins identically to [ https://mcmap.net/q/21318/-is-there-a-regexp-escape-function-in-javascript ], 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.Thegn
N
8

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');
Nicosia answered 18/8, 2019 at 3:31 Comment(1)
Much safer! And ready future Regex implementations!Stavros
I
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.

Inglorious answered 4/9, 2013 at 17:23 Comment(9)
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.Hottempered
@Hottempered I probably wouldn't either, but it is posted here for information.Inglorious
@kzh: posting "for information" helps less than posting for understanding. Would you not agree that my answer is clearer?Enriquetaenriquez
At least, . is missed. And (). Or not? [-^ is strange. I don't remember what is there.Woolly
Those are in the specified range.Inglorious
@Hottempered 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.Bedbug
@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 rangeHottempered
@Hottempered 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.Bedbug
@johnywhy this must be "readable" because most regexes are actually perfectly readable; just because you can't read them doesn't mean other people can'tKarole
A
4
escapeRegExp = function(str) {
  if (str == null) return '';
  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};
Alephnull answered 29/4, 2016 at 9:42 Comment(0)
G
4

XRegExp has an escape function:

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

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

Gev answered 5/7, 2017 at 17:58 Comment(0)
P
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).

Polack answered 1/8, 2017 at 15:36 Comment(1)
His is this different than @filip's answer? https://mcmap.net/q/21318/-is-there-a-regexp-escape-function-in-javascriptBedbug
P
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, '\\$&');
Panelboard answered 18/9, 2019 at 1:40 Comment(4)
what about ]?Impeach
Not need to be escaped, if you use a sane parser.Legator
We don't need to escape closing ] (or }) if the opening [ (or {) is escaped. Is not the same true for ) ?Pawpaw
My comment should be Why is not the same true for ) ?Pawpaw
T
1

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;
}
Teakwood answered 27/10, 2021 at 18:55 Comment(1)
Neat! Pros & cons of simple escape() function vs. tagged-template for standardization are in discussion for years: github.com/tc39/proposal-regex-escaping/issues/45 — which links to several more tagged implementations.Simonne
E
0

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.

Enriquetaenriquez answered 2/8, 2014 at 1:6 Comment(7)
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)Hottempered
@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?Enriquetaenriquez
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.Hottempered
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.Hottempered
I have escaped ` in the answer. Thanks!Enriquetaenriquez
Please address the part about closing )Hottempered
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.Woolly
R
0

This one is the permanent solution.

function regExpEscapeFuture(literal_string) {
     return literal_string.replace(/[^A-Za-z0-9_]/g, '\\$&');
}
Rovit answered 24/8, 2022 at 8:30 Comment(0)
B
0

Just published a regex escape gist based on the RegExp.escape shim which was in turn based on the rejected RegExp.escape proposal. Looks roughly equivalent to the accepted answer except it doesn't escape - characters, which seems to be actually fine according to my manual testing.

Current gist at the time of writing this:

const syntaxChars = /[\^$\\.*+?()[\]{}|]/g

/**
 * Escapes all special special regex characters in a given string
 * so that it can be passed to `new RegExp(escaped, ...)` to match all given
 * characters literally.
 *
 * inspired by https://github.com/es-shims/regexp.escape/blob/master/implementation.js
 *
 * @param {string} s
 */
export function escape(s) {
  return s.replace(syntaxChars, '\\$&')
}
Bridget answered 30/11, 2022 at 20:25 Comment(0)
M
0

Here is a replaceAll version.

Uses the string.includes function and a ternary to add the escape backslash instead of a regex.

const escapeRegexNonRegex = s => s.split('').map(a => "/-^$*+?.|()[]{}".includes(a) ? "\\" + a : a).join('');

const escapeRegex = s => s.replaceAll(/./g, a => "/-^$*+?.|()[]{}".includes(a) ? "\\" + a : a);

const usersString = "\\/-^$*+?.|()[]{}Hello";

const escapedString = escapeRegex(usersString);

const expression = new RegExp(escapedString);

const matches = usersString.match(expression);

console.log(matches);
Monolith answered 15/11, 2023 at 18:40 Comment(3)
Can you give an example of how this works ?Target
Good catch. It didn't. I presumed the "" worked in replaceAll as in split. Must have tested a split version then shortened it obviously without testing. ThanksMonolith
doesn't look "non regex based"Target
R
0

If you are a VS Code user, you can use the Replace command with regex already enabled (press Alt+R to toggle regex mode).

For example, we can escape console.log(42);:

enter image description here

Simply select a span of text and press Ctrl+H (or Ctrl+Shift+H for Search: Replace in Files).

The editor will automatically escape the selected text.

Tested with VS Code v1.87.2

Rubidium answered 12/3 at 22:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.