Character classes

Start with a concrete problem. You have a tracking code as a messy string, "[9241] 620-8837-04", and you want the bare digits: 9241620883704. The brackets, spaces, and dashes all have to go.

One clean way to do this is to describe the kind of character you care about instead of listing exact symbols. Keep the digits, drop everything else. Character classes are the tool for that.

A character class is a compact notation that matches any single character from a whole category. Instead of spelling out 0, 1, 2, …, you write one short escape that stands for “any digit”.

The digit class is written \d and matches any one digit. Here it is finding the first digit in the tracking code:

let str = "[9241] 620-8837-04";

let regexp = /\d/;

alert( str.match(regexp) ); // 9

Without the g flag, a regexp stops at the first hit. So \d here matches only the leading 7 and quits.

Add the g flag and the search sweeps the whole string, collecting every digit:

let str = "[9241] 620-8837-04";

let regexp = /\d/g;

alert( str.match(regexp) ); // array of matches: 9,2,4,1,6,2,0,8,8,3,7,0,4

// glue them into a digits-only tracking number:
alert( str.match(regexp).join('') ); // 9241620883704

The common classes

Digits are one category. There are a few more you’ll reach for constantly.

\d
a digit, 0 through 9
\s
whitespace: space, tab, newline, and a few rarer ones
\w
a “word” character: Latin letter, digit, or underscore
The three everyday character classes and what each one covers.

Here they are in more detail:

pattern:\d (from “digit”)

A digit: any character from 0 to 9.

pattern:\s (from “space”)

A whitespace character. That covers the ordinary space, tabs \t, newlines \n, and a handful of rarer characters: the vertical tab \v, the form feed \f, and the carriage return \r.

pattern:\w (from “word”)

A “word” character: a Latin letter, a digit, or the underscore _. Letters from other scripts — Cyrillic, Hindi, Greek, and so on — are not part of \w. If you need those, you’ll want the u flag and Unicode properties, covered later in this course.

To feel where each class draws its boundary, pick a class below and watch which characters in the sample light up. The tab is drawn as and each space as · so you can see them:

interactiveWhich characters belong to a class?

Because each class matches one character, you can chain them to describe a shape. The pattern pattern:\d\s\w reads as “a digit, then a whitespace character, then a word character” — it would match a substring like match:3 x.

A regexp freely mixes literal characters and character classes.

For example, pattern:USB\d matches the literal text USB followed by any digit:

let str = "Plug into USB3 here";
let regexp = /USB\d/

alert( str.match(regexp) ); // USB3

You can stack several classes together too:

alert( "We played Halo4 today".match(/\s\w\w\w\w\d/) ); // ' Halo4'

Each piece of the pattern lines up with exactly one character of the match. Walking through it left to right:

\s
\w
\w
\w
\w
\d
H
a
l
o
4
match: ’ Halo4’ (the leading box is a space)
Each class in the pattern consumes one character of the input.

Try it yourself. Edit the text or the pattern, then read off the match. Notice how removing a class or a literal from the pattern changes what lines up:

interactiveRun a pattern against a string

Inverse classes

Every class has an inverse — the same letter, uppercased. Where \d matches a digit, \D matches everything that is not a digit. Flipping the case flips the meaning.

\D
any character except a digit
\S
any character except whitespace
\W
any character except a word character
Each lowercase class and its uppercase inverse split every character into two groups.
pattern:\D

Non-digit: any character except pattern:\d. A letter, a bracket, a space — anything but 09.

pattern:\S

Non-whitespace: any character except pattern:\s, such as a letter or a digit.

pattern:\W

Non-word character: anything outside pattern:\w, such as a punctuation mark, a space, or a non-Latin letter.

Back to the tracking code. Earlier we kept the digits and joined them:

let str = "[9241] 620-8837-04";

alert( str.match(/\d/g).join('') ); // 9241620883704

The inverse class gives you a shorter route. Instead of collecting what you want, delete what you don’t: find every non-digit \D and replace it with an empty string.

let str = "[9241] 620-8837-04";

alert( str.replace(/\D/g, "") ); // 9241620883704

Same result, less work — no array to build, no join to call. When the “junk” is easier to describe than the “signal”, reach for the inverse class.

Type any messy number below and watch \D strip everything that isn’t a digit:

interactiveStrip everything but the digits

A dot is “any character”

The dot pattern:. is its own special class. It matches any single character except a newline.

alert( "Q".match(/./) ); // Q

It’s most useful as a placeholder in the middle of a pattern — a slot that says “one of something, I don’t care what”:

let regexp = /UI.5/;

alert( "UIX5".match(regexp) ); // UIX5
alert( "UI-5".match(regexp) ); // UI-5
alert( "UI 5".match(regexp) ); // UI 5 (a space counts as a character)

There’s a catch worth burning into memory: the dot means “any character”, but it still demands that a character be present. It is not “maybe a character” — the slot must be filled.

alert( "UI5".match(/UI.5/) ); // null — nothing sits between I and 5 for the dot to match

Dot as literally any character with the “s” flag

By default the dot draws one line in the sand: it will not match the newline character \n.

So pattern:X.Y wants an X, then any single non-newline character, then a Y. Put a newline in the gap and there’s no match:

alert( "X\nY".match(/X.Y/) ); // null (no match)

Often that’s not what you want — you’d like the dot to mean truly any character, newlines included. The s flag (“dotall” mode) does exactly that. Turn it on and the dot stops treating \n as special:

alert( "X\nY".match(/X.Y/s) ); // X\nY (match!)
/X.Y/
vs “X\nY” →
null
dot skips the newline
/X.Y/s
vs “X\nY” →
“X\nY”
dot matches the newline
Whether the dot matches a newline depends on the s flag.

Toggle the s flag below and watch the same pattern /A.B/ flip between null and a match against a string that has a newline in the middle:

interactiveThe s flag and the dot

Summary

The character classes covered here:

  • pattern:\d — digits.
  • pattern:\D — non-digits.
  • pattern:\s — whitespace: spaces, tabs, newlines.
  • pattern:\S — everything except pattern:\s.
  • pattern:\w — Latin letters, digits, and the underscore _.
  • pattern:\W — everything except pattern:\w.
  • pattern:. — any character, but only including newlines when the s flag is set.

That’s the core set, and it’s not the whole story. JavaScript stores strings in Unicode, and Unicode tags every character with properties: which script a letter belongs to, whether it’s punctuation, whether it’s a number, and more. Regular expressions can search by those properties too, but that needs the u flag — the subject of the next article.