cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

Character classes & sets

Learn how JavaScript regex character classes match ASCII digits, words, spaces, Unicode properties, v-flag sets, and safe user input.

By the end, you can
  • 01
    Read shorthand classes preciselyExplain what \d, \w, \s, their uppercase opposites, and dot really match.
  • 02
    Choose sets or Unicode propertiesUse ranges, negated sets, \p{L}, \p{N}, scripts, emoji properties, and \P{...} intentionally.
  • 03
    Build safer dynamic patternsEscape metacharacters correctly with a helper or ES2025 RegExp.escape, and know when the v flag is stricter.

What character classes mean

A regular expression is a sequence of positions to match. A character class describes what one position may contain: one digit, one word character, one letter from any script, one character from a bracket set, or one character outside a set.

Definition

A character class is a regex atom that matches one character from a set of allowed characters. Shorthands such as \d, bracket sets such as [a-z], Unicode properties such as \p{L}, and v-flag set operations are all ways to describe that set.

The previous lesson, Patterns & flags, covers literals, flags, test, match, and replace. This lesson stays in one lane: what counts as a character. For text background, review strings and Unicode & strings.

Common choices for one regex position
SyntaxWhat it meansBest use
\wASCII word characters: A-Z, a-z, 0-9, and _.Use for slugs, simple identifiers, and machine formats.
\p{L}Unicode letters across scripts, when used with u or v.Use for international names and text.
u flagUnicode-aware code point matching and property escapes.Needed for \p{...} and sane astral-character matching.
v flagUnicode sets: &&, --, nested classes, and string properties.Use when you need set algebra or \p{RGI_Emoji}.

Built-in classes: \d, \w, \s, and dot

STEP THROUGH

Shorthand classes are compact, but their names are easy to overread. In JavaScript, \d is ASCII digits only, \w is the ASCII word set, and \s is broader because it includes Unicode whitespace. Uppercase versions negate the class: \D, \W, and \S.

Real-life analogyA bouncer checking one guest list at a time

Think of a character class as a bouncer at one door. The bouncer does not judge the whole sentence, just the next character trying to enter this one position.

In real life: The bouncer reads one printed guest list
In JavaScript: The regex engine checks one character class
In real life: Someone either is or is not on that list
In JavaScript: A character either matches \d, \w, or the chosen set
In real life: A different door can have a different list
In JavaScript: Switching from \w to \p{L} changes the allowed set

Where the analogy stops: A bouncer checks people, not code points. Regexes also have flags, escaping rules, and string properties that can go beyond this one-door analogy.

The lab records the checks. Notice that \d skips ٣, while \p{N} accepts it; \w accepts underscore, but not é; and dot needs the s flag for newlines plus u or v for astral characters to count as one match.

Built-in class lab
Step 0 of 5Ready
Your turn: follow the blue line

Choose a built-in class, predict which labels survive, then step through the real checks.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
  ["ASCII 9", "9"],  ["Arabic ٣", "٣"],  ["A", "A"],  ["underscore", "_"],  ["space", " "],]; const labels = (regex) => samples  .filter(([, value]) => regex.test(value))  .map(([label]) => label)  .join(", "); console.log(labels(/\d/u));console.log(labels(/\D/u));console.log(/\p{N}/u.test("٣"));
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Choose the shorthand family to trace

Changing the family starts a fresh recording with source code for that exact class.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Pick a class and inspect each character
Selected class sourcePop out in the code editor (opens in a new tab)JavaScript
const sample = "A é β 9 ٣ _ -\u00A0.\n☕ 😀";const matches = sample.match(/\d/gu) ?? [];console.log(matches.join(" | "));
Matches\d

Match list: 9

Askips
characterA
spaceskips
characterspace
éskips
characteré
spaceskips
characterspace
βskips
characterβ
spaceskips
characterspace
9matches
character9
spaceskips
characterspace
٣skips
character٣
spaceskips
characterspace
_skips
character_
spaceskips
characterspace
-skips
character-
NBSPskips
characterNBSP
.skips
character.
\nskips
character\n
☕skips
character☕
spaceskips
characterspace
😀skips
character😀
Step 1 of 19\d matches

ASCII digits only: 0 through 9. The match list comes from the displayed global regular expression.

The sample includes accented letters, Greek, an Arabic-Indic digit, ordinary and non-breaking spaces, punctuation, a newline, and emoji for emoji-specific checks.
A precise note about \w

Treat \w as the ASCII word class. Unicode-aware, case-insensitive matching can case-fold a few compatibility characters, but \w is still not a Unicode letter class. Use \p{L} when the rule is “letters from human writing systems.”

Sets and ranges: [abc], [a-z0-9], and [^...]

SORT IT

Brackets make your own one-character set. [abc] means one a, b, or c. Ranges use a hyphen between endpoints: [a-z0-9] means one lowercase ASCII letter or ASCII digit. A caret immediately after [ negates the set: [^a-z0-9] means one character outside that set.

Sets and ranges in small stepsPop out in the code editor (opens in a new tab)JavaScript
console.log("cab".match(/[abc]/g).join(""));console.log("B7!".match(/[A-Z0-9]/g).join(""));console.log("B7!".match(/[^A-Z0-9]/g).join(""));console.log("a-z".match(/[a\-z]/g).join(""));

Escaping rules change inside brackets. Outside a set, ., +, ?, parentheses, braces, |, anchors, and backslash can be syntax. Inside a classic set, the big ones are ], backslash, ^ at the start, and - between endpoints. Put a literal hyphen first or last, or escape it as \-.

Name the character-class feature
  • \d
  • [a-z0-9]
  • \p{L}
  • \p{Script=Greek}
  • [\p{L}--[aeiou]]
  • \p{RGI_Emoji}
Try it yourself
0 of 6 correct

Sort each pattern by the syntax family it belongs to. This is about the class itself, not about quantifiers or groups.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Unicode properties with \p{...} and \P{...}

STEP THROUGH

Unicode property escapes require the u or v flag. Lowercase \p means “has this property.” Uppercase \P means “does not have this property.” Useful properties include \p{L} for letters, \p{Lu} for uppercase letters, \p{N} for numbers, \p{Script=Greek} for Greek script, and \p{Emoji_Presentation} for code points that default to emoji presentation.

Unicode property lab
Step 0 of 4Ready
Your turn: follow the blue line

Unicode property escapes require u or v. Pick a property family and step through exactly which text survives.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
 console.log(text.match(/\p{L}/gu).join(" "));console.log(text.match(/\p{N}/gu).join(" "));console.log(text.match(/\P{L}/gu).filter((ch) => ch !== " ").join("|"));
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Choose which property family to trace

Properties require `u` or `v`. The emoji option uses emoji only because it is demonstrating emoji properties.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Properties are not a replacement for product rules. For international names, a pattern may need letters, combining marks, spaces, apostrophes, and hyphens. For usernames, you may intentionally want ASCII only. The regex should say the policy, not guess it.

The v flag: set operations and string properties

INTERACTIVE

The v flag, also exposed as unicodeSets, builds on Unicode-aware regexes. It adds set difference with --, intersection with &&, nested classes, and string properties. A string property can match more than one code point, such as an RGI emoji sequence, as a single match.

v-flag set operations
Selected v-flag examplePop out in the code editor (opens in a new tab)JavaScript
const text = "alphabet β123";const consonantsAndGreek = text.match(/[\p{L}--[aeiou]]/gv) ?? [];console.log(consonantsAndGreek.join(""));
Outputdifference `--`
console.log 1real output
printslphbtβ
Step 1 of 4difference `--`

The v flag reads [\p{L}--[aeiou]] as letters minus lowercase ASCII vowels. Greek beta remains because it is a letter and not one of the subtracted vowels.

These examples require the v flag. The string-property option uses emoji because string properties are mainly useful for emoji sequences today.

Because v gives punctuation new meaning inside sets, it is stricter about escaping. For example, a literal | inside a v-mode set must be escaped. The next snippet throws on purpose so you can read the error and fix it to [a\|b].

A deliberate v-mode escaping errorPop out in the code editor (opens in a new tab)JavaScript
// In v mode, | is reserved inside a character class.new RegExp("[a|b]", "v");

Escaping user input and RegExp.escape

SAFE DYNAMIC REGEX

When a learner types a search term, that text is data. If you place it directly inside new RegExp(term), characters such as +, [, and ? become regex syntax. A safe highlighter escapes the term before building the regex.

Classic escape helperPop out in the code editor (opens in a new tab)JavaScript
function escapeForRegExp(input) {  return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");} const userText = "a+b [test]";const escaped = escapeForRegExp(userText);const regex = new RegExp(escaped, "g"); console.log(escaped);console.log("find a+b [test] here".replace(regex, "<mark>$&</mark>"));

ES2025 adds RegExp.escape, which is more complete than the classic helper. MDN browser-compat data lists support in Chrome 136+, Firefox 134+, Safari 18.2+, and Node.js 24+. The site tests run on Node 22, which does not have it, so server-side Node 22 code still needs the helper or a polyfill.

ES2025 RegExp.escapePop out in the code editor (opens in a new tab)JavaScript
const userText = "a+b [test]";const escaped = RegExp.escape(userText);const regex = new RegExp(escaped, "g"); console.log(escaped);console.log(regex.test("find a+b [test] here"));

Practical uses

Character classes show up in validation, cleanup, search, and tokenizing. Start with the rule in plain language: “ASCII username,” “digits from a phone field,” “letters in a human name,” or “literal search term.” Then choose the class that says exactly that.

Choosing a class for real code
ProblemPattern directionWhy
Username policy/^[A-Za-z0-9_-]+$/ or a Unicode property versionDecide whether the policy is ASCII-only before reaching for \w.
Phone digitsvalue.replace(/\D/g, "")Good for ASCII phone input; use \p{N} only if you truly accept digits from many scripts.
International names/^[\p{L}\p{M}' -]+$/uLetters and marks are broader than \w; validation still needs product rules.
Search-term highlightnew RegExp(RegExp.escape(term), "gi")User text is data, not regex syntax.
  • Usernames: ^[A-Za-z0-9_-]+$ is honest when the policy is ASCII.
  • Phone digits: value.replace(/\D/g, "") strips non-ASCII digits from common phone input.
  • Stripping punctuation: text.replace(/[^\p{L}\p{N}\s]/gu, "") keeps letters, numbers, and spaces.
  • International names: combine \p{L}, marks, spaces, and punctuation only when your product accepts them.
  • Search highlighting: escape the user term, then build the dynamic regex.

Common misconceptions

  • “\d means any digit.” In JavaScript it means ASCII 0 through 9. Use \p{N} for Unicode numbers.
  • “\w means any word letter.” It is the ASCII word set, not an international name validator.
  • “Dot means absolutely everything.” Dot skips line terminators unless the s flag is present, and astral characters need u or v to count as one code point.
  • “A bracket set matches a word.” A set matches one character. Quantifiers in the next lesson decide how many repetitions are allowed.
  • “The v flag is just u with a new name.” It adds set operations, string properties, and stricter parsing.
  • “User input is safe because it came from a text box.” Text can contain regex syntax. Escape it before building a pattern.
Similar-looking tools that solve different problems
ChoiceUse it whenDo not use it when
\wThe policy is ASCII identifiers or simple slugs.You mean letters from many scripts.
\p{L}You mean Unicode letters and have u or v.You need a tight ASCII machine format.
uYou need Unicode-aware code points and properties.You need &&, --, nested classes, or string properties.
vYou need set algebra or \p{RGI_Emoji}.A simpler u property or bracket set is clearer.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upPredict the ASCII digit output

Type the exact first line printed by this snippet.

Starter codePop out in the code editor (opens in a new tab)JavaScript
const values = ["9", "٣"];
console.log(values.filter((value) => /\d/u.test(value)).join("|"));
console.log(/\p{N}/u.test("٣"));

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeChoose the class for international letters

    The ASCII-only username regex rejects useful names. Which core class should replace \w when the rule is “letters from many scripts”?

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const names = ["maria", "maria-é", "δοκιμή"];
    const asciiOnly = /^[\w-]+$/u;
    console.log(names.filter((name) => asciiOnly.test(name)).join(","));

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticePredict the fixed username output

      Type the exact string printed by the corrected filter.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      const names = ["maria", "maria-é", "δοκιμή"];
      const international = /^[\p{L}\p{N}_-]+$/u;
      console.log(names.filter((name) => international.test(name)).join(","));

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeRead a v-flag set difference

        Predict the output from the `v`-flag difference.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        const text = "a b c x y z";
        console.log(text.match(/[[a-z]--[aeiou]]/gv).join(""));

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeChoose the safe dynamic-regex tool

          A user searches for a+b. Which ES2025 method should you call before building the regex?

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          const term = "a+b";
          const unsafe = new RegExp(term);
          console.log(unsafe.test("aaab"));

          Answer, then press Check. Spacing and letter case don’t matter.

            Check your understanding

            8 QUESTIONS
            Lesson quiz · 8 questionsScore: first tries count
            1. Question 1 of 8What does \d match in JavaScript?

              Choose an answer to see the explanation.

            2. Question 2 of 8What does the word-class snippet print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const values = ["é", "_", "A"];
              console.log(values.filter((value) => /\w/u.test(value)).join(","));

              Choose an answer to see the explanation.

            3. Question 3 of 8What does dot print for this astral-character example?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log("😄".match(/./g).length, "😄".match(/./gu).length);

              Choose an answer to see the explanation.

            4. Question 4 of 8What does the range snippet print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log("aB7-".match(/[a-z0-9]/g).join(""));

              Choose an answer to see the explanation.

            5. Question 5 of 8Which output comes from this Greek script check?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log("A β Ж".match(/\p{Script=Greek}/gu).join(""));

              Choose an answer to see the explanation.

            6. Question 6 of 8What does this v-flag set difference print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const text = "a b c x y z";
              console.log(text.match(/[[a-z]--[aeiou]]/gv).join(""));

              Choose an answer to see the explanation.

            7. Question 7 of 8Why should a search highlighter escape user input before new RegExp?

              Choose an answer to see the explanation.

            8. Question 8 of 8Which runtime fact is true for RegExp.escape?

              Choose an answer to see the explanation.

            Key takeaways

            • \d and \w are ASCII shorthands; \s includes Unicode whitespace.
            • Dot skips line terminators without s, and astral characters need u or v to match as one code point.
            • Bracket sets match one character; ranges and negation describe which one.
            • Unicode properties such as \p{L}, \p{Lu}, \p{N}, and \p{Script=Greek} require u or v.
            • The v flag adds set operations, nested classes, string properties, and stricter escaping.
            • Escape user input with a helper or RegExp.escape before building a dynamic regex.

            Remember the one-liner.
            Say the character set you mean in plain language, then choose the regex syntax that matches exactly that set.

            Up next: Quantifiers, where the class you just chose can repeat with +, *, ?, and {n,m}.

            CompleteFrontend Clear concepts. Working examples.