A character class matches one character from a set of allowed characters. "Any vowel," "any digit," "any letter from a to f": classes are how a single position in a pattern can accept more than one thing.
/[aeiou]/ // any one vowel
/gr[ae]y/ // "gray" or "grey"
/[0-9]/ // any one digit (a range)
/[a-z]/ // any lowercase letter
/[A-Za-z0-9]/ // any letter or digit (ranges combine)
"grey gray groy".match(/gr[ae]y/g) // ["grey", "gray"]
"Banana".match(/[aeiou]/gi).length // 3 vowels
[abc] matches "a" or "b" or "c", never "abc". To match several in a row you add a quantifier (covered in RegExp Quantifiers): [abc]+.
A ^ right after the opening bracket flips the meaning:
/[^aeiou]/ // any character that is NOT a vowel
/[^0-9]/ // any non-digit
"h3ll0 w0rld".replace(/[^a-z ]/g, "*") // "h*ll* w*rld"
console.log("Hello World!".match(/[HW]/g));
console.log("This is W3School".match(/[A-Z]/g));
console.log("123456789".match(/[1-4]/g)); // same as [1234]
console.log("abcdef".match(/[^a-c]/g)); // NOT a, b, or c
A range is a shortcut for listing: [0-4] is the same as [01234], and [a-e] is the same as [abcde].
[abc] "matches all characters between the brackets." It matches any one of them per position. "abc".match(/[abc]/)[0] is "a", not "abc".
These come up so often they have built-in shortcuts:
| Class | Matches | Same as |
|---|---|---|
| \d | Digit | [0-9] |
| \w | "Word" character | [A-Za-z0-9_] |
| \s | Whitespace | space, tab, line break... |
| \D \W \S | The opposite of each (capital = NOT) | [^0-9] etc. |
| . | Any character except a line break |
"Room 4B, floor 12".match(/\d/g) // ["4", "1", "2"]
"a b\tc".split(/\s+/) // ["a", "b", "c"]
"x_1-y@2".match(/\W/g) // ["-", "@"]
\w only knows English letters. It does not match accented letters like "é" or "ñ". "café".match(/\w+/)[0] is "caf". For real-world names and words, use the Unicode classes below.
With the u flag, \p{...} matches characters by category, in every language:
"café naïve".match(/\p{L}+/gu) // ["café", "naïve"] \p{L} = any letter
"Straße".match(/\p{Lu}/gu) // ["S"] \p{Lu} = uppercase letter
"Hi 👋 there 🎉".match(/\p{Emoji_Presentation}/gu) // ["👋", "🎉"]
Inside square brackets most symbols lose their special meaning. Only a few need care:
/[.?!]/ // a period, question mark, or exclamation point (no escaping needed)
/[-+]/ // a hyphen FIRST or LAST is literal
/[a\-z]/ // escaped hyphen: "a", "-", or "z" (not a range)
/[\]]/ // a closing bracket must be escaped
// A simple product code: 3 capital letters, a dash, 4 digits
const code = /^[A-Z][A-Z][A-Z]-\d\d\d\d$/;
code.test("ABC-1234") // true
code.test("abc-1234") // false
code.test("AB-12345") // false
Writing [A-Z] three times works but is repetitive. Quantifiers (later) shorten it to [A-Z]{3}.
What does this log?
console.log("B2B for 4U".match(/[A-Z0-9]/g).join(""));
B2B4U. The class matches one capital letter or digit at a time, in the order they appear. Lowercase letters and spaces are skipped.Which one matches "grey" and "gray" but not "groy"?
/gr.y//gr[ae]y//gr[^ae]y//gr[a-z]y/Why does "José".match(/\w+/)[0] give "Jos"?
\w skips capital letters\w only knows A-Z, a-z, 0-9, and _+ stops after 3 charactersmatch drops the last character/\p{L}+/u to match letters in any language.\s+\w+ and \p{L}+ (with the u flag) on "Zoë and Ángel"