iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Character Classes

A character class matches one character from a set. [abc] matches a, b, or c; [a-z] any lowercase letter; [^...] negates. Built-in shortcuts like \d, \w, \s, plus Unicode property escapes, cover almost everything you need.

Sets, ranges, negation, Unicode

EXAMPLE
// 1) Basic sets
/[aeiou]/.test('hello')          // true   — any vowel
/[aeiou]/g.exec('hello')          // ['e']  — first vowel
'aeiou'.match(/[xyz]/)            // null

// 2) Ranges
/[a-z]/.test('Hello')             // true   — 'e' is lowercase
/[A-Z]/.test('hello')             // false
/[a-zA-Z]/.test('Hello')          // true
/[0-9]/.test('order42')           // true
/[a-fA-F0-9]/.test('1c')          // true   — hex digit

// 3) Negated set
/[^aeiou]/.test('aeiou')          // false
/[^0-9]/.test('123abc')           // true   — 'a'
/[^aeiou ]/g.exec('hello world')   // matches consonants and the space

// 4) Escaping inside character classes
//   ]    must be escaped:  /[\]]/
//   \    must be escaped:  /[\\]/
//   -    only special between two chars; put first or last to use literally: /[-a-z]/, /[a-z-]/
//   ^    only special as the FIRST char (negation); literal elsewhere: /[a^b]/

// 5) Built-in shortcuts
//   \d   digit            equivalent to [0-9]
//   \D   non-digit         [^0-9]
//   \w   word              [A-Za-z0-9_]
//   \W   non-word
//   \s   whitespace        space, tab, newline, etc.
//   \S   non-whitespace
//   .    any except \n (without dotall flag)

/^\d{3,4}-\d{4}$/.test('555-1234')   // true   — phone-like
/[\w.+-]+@[\w-]+\.\w+/.test('a@b.co')  // true   — simple email shape

// 6) Unicode property escapes (with /u flag — JS, modern engines)
/^\p{L}+$/u.test('Привет')           // true   — any letter
/^\p{N}+$/u.test('一二三')           // true   — any numeric character
/\p{Emoji}/u.test('hi 👋')             // true
/\p{Script=Greek}/u.test('αβγ')        // true
/\P{Cn}/u                              // anything assigned (negate 'unassigned')

// 7) ASCII vs Unicode \w
// Default \w in JS is [A-Za-z0-9_] — no accents, no emoji, no CJK.
/\w+/u.test('café')                    // matches 'caf' then 'café' splits — wait, depends on engine
// To match Unicode letters, use \p{L} instead.
/^[\p{L}\p{N}_]+$/u.test('café_42')   // true

// 8) Combining sets — union and intersection
// Union — easy, just list both ranges
/[A-Za-z0-9]/
// Intersection — needs the v flag (modern engines) or workaround
/[\p{Letter}&&\p{ASCII}]/v.test('é')    // false   — letter intersected with ASCII
// Without the v flag, write the explicit range you want.

// 9) Common patterns built from character classes
//   Hex color        /^#[0-9a-fA-F]{3,8}$/
//   Slug             /^[a-z0-9]+(?:-[a-z0-9]+)*$/
//   UUID             /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
//   IPv4 octet       /^25[0-5]|2[0-4][0-9]|1?[0-9]{1,2}$/    (one octet, used 4x)
//   Base64           /^[A-Za-z0-9+/=]+$/

// 10) POSIX classes (some engines — not JS by default)
//   [:alpha:]  letters
//   [:digit:]  digits
//   [:upper:]  upper-case
//   [:space:]  whitespace
//   [:punct:]  punctuation
//   Used as /[[:alpha:]]/ — JS doesn't support these natively.

// 11) Whitespace gotchas
//   \s matches \u00a0 (non-breaking space), tabs, line separators
//   In some engines \s includes Unicode whitespace; in others ASCII only
//   Use [\s\u200B-\u200D] to also catch zero-width spaces when scrubbing

// 12) Newlines
//   . matches any except \n by default
//   Use the s flag (dotall): /^foo.bar$/s.test('foo\nbar')   → true

// 13) Real-world examples
// Detect simple credit-card patterns (use a library for real validation; Luhn check required)
/^(?:\d[ -]?){13,19}$/.test('4111 1111 1111 1111')

// Match a single Unicode word boundary correctly (best-effort)
/^\p{L}[\p{L}\p{N}\p{Mn}_'-]*$/u.test("O'Hara-Smith")

// Strip non-printable control characters before storing
function sanitize(s) {
    return s.replace(/\p{C}/gu, '');     // \p{C} = control + format + private use + unassigned + surrogate
}

// 14) Performance tips
//   • A class with many alternatives is faster than | alternation: prefer [abc] over (a|b|c)
//   • Avoid nested quantifiers + negated classes (catastrophic backtracking risk)
//   • Anchor patterns (^, $, \b) to give the engine a fixed starting position
//   • Compile once if your runtime allows it (don't rebuild per call inside a loop)

// 15) Common bugs
//   • [0-9] inside an Unicode-only ranged set — accidentally matches digits from other scripts when /u is set
//   • Forgetting to escape ] inside a class on engines that require it
//   • Putting - in the middle of a class without intending a range: [a-z] is a range, [-az] / [az-] are literals
//   • Using \d expecting only ASCII — with /u, \d still ASCII; \p{Nd} is the Unicode equivalent
//   • Negating with [^] expecting an empty class — that matches ANY character (most engines)
//   • Building dynamic regex with unsanitised input — escape with /[.*+?^=!:{}()|\\[\\]\\/\\\\]/g.replace(...)

Why it matters

Pick character classes over alternations — [abc] is one decision per char, (a|b|c) is three. Use \d, \w, \s for ASCII-only fields, switch to \p{L}, \p{N}, \p{Emoji} with the /u flag whenever real human text shows up, and remember that JS’s default \w doesn’t match accented letters.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
[abc]      // a, b, or c
[^abc]     // anything except a, b, c
[a-z0-9]   // a–z OR 0–9
\d  \D    // digit / non-digit
\w  \W    // word char / non-word
\s  \S    // whitespace / non-whitespace
Try it Yourself »

Exercise

Escape for any digit 0-9.

/ +/

Discussion

Loading…