/^/

Lesson 4 of 28

Character Classes

Matching one of several characters at a position using [...], negation with [^...], ranges, and the \d \w \s shorthand classes.

6 min read

A literal like cat matches one exact character at each position. A character class matches any one character from a set you define, using square brackets. [aeiou] matches a single vowel — not all five in a row, just one character that happens to be one of those five.

/[aeiou]/.test("sky");   // false — no vowel in "sky"
/[aeiou]/.test("cat");   // true — matches the "a"
hello world
3 matches

With the g flag, the demo finds every vowel in the string individually — e, o, o — because each match consumes just one character before the engine moves on to look for the next one.

Ranges

Inside [...], a hyphen between two characters defines a range, so you don’t have to list every character by hand. [a-z] matches any lowercase letter, [A-Z] any uppercase letter, [0-9] any digit, and you can combine ranges: [a-zA-Z0-9] matches any letter or digit.

/[a-z]/.test("HELLO");    // false — no lowercase letters
/[a-zA-Z0-9]/.test("!!!"); // false — no letters or digits at all

Negation with [^...]

Putting a caret ^ immediately after the opening bracket flips the meaning: the class now matches any character not in the set.

/[^0-9]/.test("42");    // false — every character is a digit
/[^0-9]/.test("42a");   // true — the "a" isn't a digit
abc123
3 matches

The demo matches a, b, and c — everything in "abc123" that isn’t a digit — and correctly skips over 1, 2, 3.

Watch out

A caret only means “negate” when it’s the very first character inside the brackets. [a^z] matches a, ^, or z literally — the caret has no special meaning there because it’s not in the first position.

Shorthand classes

Because certain character classes come up constantly, regex gives them single-letter shortcuts:

Shorthand Equivalent to Matches
\d [0-9] Any digit
\D [^0-9] Any non-digit
\w [a-zA-Z0-9_] Any “word” character (letters, digits, underscore)
\W [^a-zA-Z0-9_] Any non-word character
\s [ \t\n\r\f\v] Any whitespace (space, tab, newline, etc.)
\S [^ \t\n\r\f\v] Any non-whitespace

These are especially handy combined with the quantifiers you’ll meet next lesson — \d+ means “one or more digits in a row”:

Order #12345 costs $67.89
3 matches

The demo pulls out 12345, 67, and 89 as three separate digit runs, stopping each match as soon as it hits a non-digit character.

The dot: match (almost) anything

You saw the dot . briefly in the last lesson — it’s technically its own thing, not a character class, but it behaves similarly: it matches any single character except (by default) a newline.

/c.t/.test("cat");  // true
/c.t/.test("cot");  // true
/c.t/.test("ct");   // false — dot requires exactly one character
cat cot cut c t
4 matches

Notice the last match: c.t even matches "c t" (with a literal space between them), because the dot doesn’t care which character it matches, only that there’s exactly one.

Try it yourself

Using the demo above, change the pattern from c.t to c[aeiou]t — a character class instead of a dot. Compare which lines still match.

What should happen

c[aeiou]t only matches cat and cot (and would match cut, cet, cit too) because the middle character is restricted to vowels — the "c t" match disappears since a space isn’t in the [aeiou] set. This is the key difference between the dot (any character at all) and a character class (a specific, chosen set of characters).

What’s next

Character classes control which characters can appear at a position. The next lesson covers anchors^, $, and \b — which control where in the string a match is allowed to happen.

Quick check

What does the pattern [^aeiou] match?

Which shorthand class is equivalent to [0-9]?