toolhq.io

All posts
5 min readby Jameel Haider

Regex character classes explained

A character class is the part of a regular expression wrapped in square brackets, and it matches exactly one character from the set you describe. [aeiou] matches a single vowel. This is the most common point of confusion for people new to regex, because the rules inside brackets are deliberately different from the rules outside them.

Sets and ranges

Inside [...], you list the characters you want to allow. [abc] matches a, b, or c. For contiguous runs you use a range with a hyphen: [a-z] is every lowercase letter, [0-9] every digit, [A-Za-z0-9] every alphanumeric ASCII character. The order matters only in that the left side must sort before the right side; [z-a] is an error in most engines.

A hyphen is only a range operator when it sits between two characters. At the start or end of the class it is a literal: [-a-z] and [a-z-] both include a literal hyphen plus the letter range.

Negation with a caret

A caret as the first character negates the whole class. [^0-9] matches any single character that is not a digit. The caret only has this meaning in the first position. [a^] matches a or a literal caret. A common mistake is reading [^abc] as "nothing" when the input is empty; a negated class still requires one character to be present, it just must not be one of the listed ones.

What loses its special meaning inside brackets

Most metacharacters are literal inside a character class. This surprises people constantly.

CharacterOutside bracketsInside brackets
.any characterliteral dot
* + ?quantifiersliteral symbols
( )groupingliteral parentheses
|alternationliteral pipe
$end anchorliteral dollar

So [.?] matches a literal dot or a literal question mark, not "any character or one optional thing". The characters that still need escaping inside a class are ] (close the class), \ (the escape itself), ^ (only if first), and - (only between two characters). A backslash still introduces escapes, so [\n\t] matches a newline or tab.

Shorthand classes

The engine ships predefined classes for common sets:

  • \d is a digit, equivalent to [0-9] in ASCII mode.
  • \w is a word character, [A-Za-z0-9_].
  • \s is whitespace, including space, tab, newline, and a few others.

Their uppercase forms are the negations: \D is a non-digit, \W a non-word character, \S non-whitespace. You can combine shorthands inside a class: [\w.] matches word characters or a literal dot, which is handy for simple identifier or filename matching.

Be careful with \d in Unicode-aware modes. In JavaScript with the u flag or in .NET by default, \w and \d may match characters beyond ASCII unless you constrain them, so test against the exact input you expect.

POSIX classes

Some engines (PCRE, grep, Ruby) support POSIX bracket expressions like [[:alpha:]], [[:digit:]], and [[:alnum:]]. Note the double brackets: [:alpha:] is itself a class, so you write [[:alpha:]] to use it, and you can combine it, as in [[:alpha:]_]. JavaScript does not support POSIX classes, so prefer \w, \d, and explicit ranges for portable patterns.

The fastest way to build confidence here is to watch matches update as you edit the brackets. Paste a sample string and experiment with ranges, negation, and shorthands in the Regex Tester.