SKU // 88

JavaScript RegExp Metacharacters

Metacharacters are symbols with a special meaning inside a regex. They are what make patterns powerful, and also what makes searching for a literal dot or question mark tricky. This lesson maps every one and shows how to switch off their special meaning when you need the plain character.

// The Metacharacters

Symbol Meaning Lesson
.Any character except a line breakhere
|OR: this or thathere
\Escape: next character is literal (or a shorthand like \d)here
[ ]Character classClasses
^ $Start / end of textAssertions
( )GroupGroups
* + ? { }How many timesQuantifiers

// The Dot: Any One Character

/c.t/.test("cat")    // true
/c.t/.test("c9t")    // true
/c.t/.test("c t")    // true  (a space is a character too)
/c.t/.test("ct")     // false (the dot needs exactly one character)
true true true false

// The Pipe: Alternatives

/cat|dog|bird/.test("I have a dog")     // true
"jpg png gif bmp".match(/jpg|png|gif/g)    // ["jpg", "png", "gif"]
Watch out
| splits the whole pattern unless you group it. /^cat|dog$/ means "starts with cat" OR "ends with dog," not "is exactly cat or dog." Use a group: /^(cat|dog)$/.

// Escaping: Matching the Literal Character

To search for an actual dot, question mark, or other metacharacter, put a backslash before it:

/3.14/.test("3514")     // true   (oops: . matched "5")
/3\.14/.test("3514")    // false
/3\.14/.test("3.14")    // true

/\$\d+/.test("$25")     // true   literal dollar sign, then digits
/\(\d{3}\)/              // literal parentheses around 3 digits: "(410)"
true false true true

Characters that need escaping outside brackets:

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

// Escaping User Input

If you build a regex from text someone typed, any metacharacters in it will be treated as pattern symbols. Escape them first:

function escapeRegExp(text) {
  return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

const search = "C++";
const re = new RegExp(escapeRegExp(search), "g");

"I like C++ and C#".match(re)   // ["C++"]
["C++"]
Reading the Code
The pattern is a class listing every metacharacter. In the replacement, $& means "the matched text," and "\\" is one backslash in a string. So each metacharacter gets a backslash put in front of it. Without this, new RegExp("C++") throws a SyntaxError.
New in 2025: RegExp.escape()
Current browsers now have this built in. RegExp.escape("C++") returns a safely escaped pattern string, so new RegExp(RegExp.escape(search), "g") does the same job as escapeRegExp. (It also escapes a leading letter or digit in an unusual way, like \x43 for C, which is still correct.) Older browsers do not have it, so the hand-written function is still worth knowing.

// Special Escape Sequences

\nLine break
\tTab
\d \w \s (and \D \W \S)Shorthand classes
\b \BWord boundary (next lesson)
"line1\nline2\nline3".split(/\n/)   // ["line1", "line2", "line3"]
"name\tage\tcity".split(/\t/)      // ["name", "age", "city"]

// Shorthand Classes in Action

W3Schools groups the backslash shorthands with the metacharacters. Capital letters mean NOT:

const text = "Give 100%!";

console.log(text.match(/\d/g));    // digits
console.log(text.match(/\D/g));    // NOT digits (the space counts)
console.log(text.match(/\w/g));    // word characters
console.log(text.match(/\W/g));    // NOT word characters
console.log("Is this all there is?".match(/\s/g).length);   // spaces
["1", "0", "0"] ["G", "i", "v", "e", " ", "%", "!"] ["G", "i", "v", "e", "1", "0", "0"] [" ", "%", "!"] 4

// Characters by Their Code

Every character has a number. You can match a character by that number, written in hexadecimal (base 16):

\xhhTwo hex digits\x6F is "o"
\uhhhhFour hex digits\u0057 is "W"
\u{h...}Any number of hex digits (needs the u flag)\u{1F600} is "😀"
const s = "Visit W3Schools. Hello World!";
console.log(s.replace(/\x6F/g, "*"));
console.log(s.match(/\u0057/g));
console.log(/\u{1F600}/u.test("😀"));
Visit W3Sch**ls. Hell* W*rld! ["W", "W"] true
Not recommended: octal \ddd
W3Schools also lists \ddd, a character by its octal (base 8) number: /\101/ matches "A". This is a leftover from old JavaScript. It is easy to confuse with a group reference like \1 (RegExp Groups), and with the u flag it is not allowed at all: /\101/u is SyntaxError: Invalid regular expression: /\101/u: Invalid escape. Use \x41 or \u0041 instead.

// Quick Check

Which pattern matches the exact text "1+1=2"?

  1. /1+1=2/
  2. /1\+1=2/
  3. /1[+]1=2/
  4. Both B and C
Show answer
D. In A, + means "one or more 1s," so it matches "11=2" but not "1+1=2". Escaping with a backslash or putting + in a class both make it literal.

What does this log?

console.log(/^(cat|dog)$/.test("catalog"), /^cat|dog$/.test("catalog"));
Show answer
false true. Without the group, the second pattern means "starts with cat" OR "ends with dog," and "catalog" starts with cat.

What happens with new RegExp("C++")?

  1. It matches "C++"
  2. It matches "C" followed by one or more "+"
  3. SyntaxError: Nothing to repeat
  4. It matches nothing, with no error
Show answer
C. The second + has nothing to repeat. Escape user input first with escapeRegExp or RegExp.escape.

// Try It

  1. Click Open Playground and run it. Then fix the pattern so it only matches "1.5"
  2. Write a pattern that matches any of the file extensions ".jpg", ".png", or ".gif" at the end of a name
  3. Try new RegExp("?") and read the error, then fix it with escapeRegExp
  4. Match a price like "$19.99" with escaped $ and .
// Video Walkthroughs
Last updated: Oct 10, 2026, 1:46 AM ET