Escaping, special characters

A backslash inside a regular expression is a signal, not a literal character. You’ve already met it in character classes like pattern:\d (a digit) or pattern:\s (whitespace). The backslash tells the regexp engine: “the next character means something special.” That makes the backslash itself special, exactly the way it is inside ordinary JavaScript strings.

The backslash has company. A whole set of characters carry special meaning inside a pattern:

[ ] { } ( ) \ ^ $ . | ? * +

Each one is a tool for building more expressive searches: pattern:. matches any character, pattern:* repeats, pattern:| means “or”, and so on. You’ll meet every one of them across the regexp chapters. There’s no need to memorize the list now, and no need to understand what each does yet. The point of this article is different: what happens when you want one of these characters to mean itself, and nothing more.

[]{}()\^$.|?*+
The regexp metacharacters — each has a job in pattern syntax, so matching one literally needs a backslash.

Escaping

Suppose you want to find a literal dot in some text. Not “any character” (which is what pattern:. normally means), but an actual period.

The rule is simple: put a backslash in front of the special character. So a literal dot becomes pattern:\.. This is called escaping the character. The backslash strips the character of its special powers and leaves it as plain text.

alert( "Build 7.3".match(/\d\.\d/) ); // 7.3 (match!)
alert( "Build 733".match(/\d\.\d/) ); // null (no real dot to match)

Read pattern:/\d\.\d/ as three requirements in a row: a digit, then a literal dot, then a digit. "Build 7.3" contains 7.3, which fits. "Build 733" has three digits but no dot, so there’s nothing for pattern:\. to match.

.
matches ANY
single character
→ add \ →
\.
matches a literal
dot only
Escaping flips a metacharacter from 'special' to 'literal'.

Toggle the escape below to feel the difference. With the dot escaped, the pattern demands a real period; without it, the dot matches any character at all, so even 511 slips through.

interactiveEscaped dot vs. bare dot

Parentheses are special too (they group parts of a pattern), so to match real parentheses you escape both. Here’s a pattern that finds the literal text box():

alert( "draw box()".match(/x\(\)/) ); // "x()"

The pattern pattern:/x\(\)/ reads as: the letter x, then a literal (, then a literal ). Without the backslashes, pattern:() would be an empty capturing group and wouldn’t match those characters at all.

Matching a backslash itself

What if the thing you’re hunting for is a backslash? It’s special in two places at once: inside the regexp and inside a normal JavaScript string. To match one literal backslash, the pattern needs a doubled backslash pattern:\\.

alert( "p\\q".match(/\\/) ); // '\'

Notice the string "p\\q" also uses two backslashes, but for a different reason. In the string literal, \\ produces a single backslash character, so the actual text in memory is p\q. The pattern pattern:/\\/ then matches that single backslash. Two layers, two sets of doubling, both landing on one real backslash.

A slash

The slash / is not a regexp metacharacter. It matches nothing special on its own. But JavaScript uses it as the delimiter for regexp literals: pattern:/...pattern.../. So inside a pattern:/.../ literal, a bare / would be read as “end of pattern” and confuse the parser. You escape it to keep it as literal text.

alert( "3/4".match(/\//) ); // '/'

Think of the outer slashes as quotes around the pattern. Just as a quote character inside a string literal has to be escaped, a slash inside a slash-delimited regexp has to be escaped.

/\//← the escaped slash is pattern data, the outer slashes are delimiters
Inside a /.../ literal, an unescaped slash would close the pattern early — the backslash keeps it as data.

There’s an exception. If you build the regexp through new RegExp from a string instead of a pattern:/.../ literal, the slash is no longer a delimiter, so it needs no escaping:

alert( "3/4".match(new RegExp("/")) ); // finds /

new RegExp

Building patterns from strings with new RegExp frees you from escaping slashes, but it introduces a different escaping trap — one that catches almost everyone the first time.

Look at this, which seems like it should work but doesn’t:

let regexp = new RegExp("\d\.\d");

alert( "Build 7.3".match(regexp) ); // null

The equivalent literal pattern:/\d\.\d/ matched 7.3 earlier. So why does new RegExp("\d\.\d") fail? The regexp engine never sees the backslashes. They’re gone before the string ever reaches new RegExp.

Here’s the reason. A string literal has its own escaping rules, and its own idea of what a backslash means. When JavaScript parses "\d\.\d", it processes those backslashes as a string first, long before any regexp exists.

alert("\d\.\d"); // d.d

The quotes “consume” each backslash and interpret it:

  • \n becomes a newline character
  • a Unicode escape like \u1234 becomes the single character at that code point
  • and when a backslash sits in front of something with no defined escape meaning, like \d or \z, the backslash is simply dropped and the plain character remains

So "\d\.\d" collapses to the string d.d. That’s the value handed to new RegExp, which dutifully builds a pattern that looks for the literal text d.d. No wonder it can’t find 7.3.

what you wrote
“\d\.\d”
↓ string parser reads escapes
string value new RegExp receives
d.d
↓ regexp engine compiles it
pattern that actually runs
matches the literal text “d.d” — not what you meant
Two-stage processing: the string parser eats the backslashes before new RegExp ever runs.

The fix is to double every backslash in the source string. Since the string parser turns \\ into a single \, doubling means one real backslash survives to reach the regexp engine:

let regStr = "\\d\\.\\d";
alert(regStr); // \d\.\d (correct now)

let regexp = new RegExp(regStr);

alert( "Build 7.3".match(regexp) ); // 7.3

Now the string value is \d\.\d, exactly the pattern text you wanted, and the match works.

See both versions run side by side. The source property reveals the pattern text the engine actually compiled — for the single-backslash string it has already collapsed to d.d, which explains the missing match.

interactiveWhy new RegExp needs doubled backslashes

The classic runtime use is exactly the one named above: taking whatever a person typed and hunting for it literally, even when it contains metacharacters. That means escaping every special character before building the pattern. Type a term below — including one with $, ., or + — and watch it get escaped and highlighted in the sample text.

interactiveEscaping a user's search term

Summary

  • To match a special character pattern:[ \ ^ $ . | ? * + ( ) literally, put a backslash in front of it — “escape” it. The backslash removes its special meaning.
  • Escape / as well when you write it inside a pattern:/.../ literal, because the slashes delimit the pattern. Inside new RegExp, the slash needs no escaping.
  • When you pass a pattern as a string to new RegExp, double every backslash (\\). The string parser consumes one backslash of each pair, so the doubling is what lets a single backslash survive into the compiled regexp.