Concepts / Character Classes and Anchors

Character Classes and Anchors

Many learners meet a character class name such as digit and assume that writing the name by itself is enough to match a digit.

  • Programming

Testing a Common Belief About Class Names

Many learners meet a character class name such as digit and assume that writing the name by itself is enough to match a digit. The belief is understandable, because in everyday language a digit is a decimal digit. In a regular expression, however, the notation has its own rules, and the bare name does not carry the full meaning. This article starts by testing that belief, then builds the correct picture from the rules that the notation defines.

What do you think happens?

Suppose a pattern consists only of the bare class name [:digit:]. Will that pattern match the character 5?

  • Yes, because digit already means a decimal digit

  • No, the bare name is not a complete match instruction

Reveal answer
Answer:

No. The bare name is not a complete match instruction. The class name must be used within a bracket pair, which gives [[:digit:]].

The name describes a set of characters, but the regular expression engine only recognizes that set as a class when the name sits inside the outer bracket pair. The rest of this article explains why.

Pieces Match Once by Default

When you write a pattern, each piece of it normally matches exactly once. The default, when no suffix is added, is exactly once. This means a suffix is the only way to tell a matcher that a piece should occur a different number of times. Without a suffix, a piece such as the letter a is read as one a, and no more and no fewer.

A suffix attaches to the piece in front of it and states how many consecutive occurrences are allowed. Once you can read those suffixes fluently, you can describe patterns such as three of these, no more and no fewer, or at least one of these, directly in the pattern itself. You do not need to write out the repeated piece many times.

Six Repetition Notations

There are six notations in total. The first three use braces and take explicit numbers. The last three are symbols that stand for common counts. The table below gives each notation, its meaning in words, and its equivalent brace form where one is given.

NotationMeaning in wordsEquivalent brace form
{n}exactly n occurrencesnot applicable
{n,}at least n occurrences (open minimum)not applicable
{n,m}between n and m occurrences (bounded range)not applicable
* (asterisk)zero or more occurrences{0,}
+ (plus sign)one or more occurrences{1,}
? (question mark)zero or one occurrence{0,1}

The six repetition notations and what each one allows

Checking a String Against a Count

Deciding whether a string matches a pattern comes down to counting. A string fails a pattern when any single piece has the wrong count. The matcher reads the string, consumes occurrences of the piece while the count allows, and fails when the string offers more occurrences than the notation permits or fewer than it requires.

Worked example

Does aaaa fit the piece a{2,3} in full?

Test whether the string aaaa matches the piece a{2,3} across all of its characters.

  1. 1
    Read the allowed range

    The notation {2,3} is a bounded range. It allows two occurrences of a at minimum and three at maximum.

  2. 2
    Count the occurrences in the string

    The string aaaa contains four consecutive a characters.

  3. 3
    Compare the count with the range

    Four is above the maximum of three, so the piece cannot account for the whole string.

Result

No match. The count of a is too high for the notation a{2,3}.

read first acount 1 of 2read second acount 2 of 2count reachedno more a allowedthird a arrivesone too manyno matchstring does not matchconsumelimit hitanother areject
What happens at each step when the matcher reads the string aaa against a piece whose count is exactly two?

The same logic explains the failures that the source annotates. The source gives the string AAABBBBBCCC as an example that does not match its pattern and annotates it as having too many Bs. Each annotation identifies a single letter whose count is off, so the annotation tells you which piece of the pattern has the wrong count, and that piece is the one to revisit.

Why the Class Name Needs Brackets

A character class is an entry in a list of named sets of characters. The list covers things like alphanumeric characters, alphabetic characters, whitespace, punctuation, and hexadecimal digits. Each name describes a set, and the set is what the pattern matches. The name must be written in a particular way for the engine to recognize it as a class rather than as ordinary text.

The notation works in two layers. The inner layer is the class name, wrapped in the delimiters [: and :]. The outer layer is an ordinary bracket pair, [ ], which marks the whole construction as a character class inside the pattern. The class name [:digit:] matches a decimal digit, but it must be used within a bracket pair to form a working expression, giving [[:digit:]].

[outer bracket pair opens[:class name opensdigitthe set: decimal digits:]class name closes]outer pair closes
How is the named class nested inside the outer bracket pair, and what would be missing without that pair?

Shorthand Escapes and Their Classes

Writing [[:digit:]] every time is precise but verbose, so the notation provides shorthand forms for several common classes. Each shorthand is a backslash followed by a letter. The shorthand \d stands for [[:digit:]], \s stands for [[:space:]], and \w stands for [_[:alnum:]]. The uppercase forms match the complements of these sets. In a negated form, the caret inside the bracket is the negation marker, so \D is the complement of \d and matches anything that is not a decimal digit.

\dshorthand key[[:digit:]]decimal digit\sshorthand key[[:space:]]whitespace\wshorthand key[_[:alnum:]]letters, digits, underscore\Dnegated shorthand[^[:digit:]]not a decimal digit\Snegated shorthand[^[:space:]]not whitespace\Wnegated shorthand[^_[:alnum:]]not a letter, digit, orunderscoreexpands toexpands toexpands tocomplementcomplementcomplement
Which bracketed character class does each shorthand escape stand for, and which entries are the negated forms?

The class \w is the one most often misread, because its name suggests letters alone. The definition covers three things: a letter from a to z, a digit from 0 to 9, and an underscore. The expansion [_[:alnum:]] combines the underscore with the alphanumeric class. A learner who reads \w as just letters will be surprised when a digit or an underscore matches.

Worked example

Does \w match each of three characters?

Decide whether \w matches the characters q, 7, and an underscore, and whether it matches a hyphen.

  1. 1
    List the set

    \w matches a letter from a to z, a digit from 0 to 9, or an underscore.

  2. 2
    Test the letter q

    q is a letter from a to z, so it is in the set.

  3. 3
    Test the digit 7

    7 is a digit from 0 to 9, so it is in the set even though the name suggests letters.

  4. 4
    Test the underscore and the hyphen

    The underscore is in the set. The hyphen is none of the three, so it is not in the set.

Result

\w matches q, 7, and the underscore, and does not match the hyphen.

Nonstandard Abbreviations and Portability

Beyond the standard shorthand, languages that support regular expressions often provide additional abbreviations. These are described as nonstandard but common. The lowercase and uppercase forms are \l and \u, and their negations are \L and \U. The escape \l stands for a lowercase character, which corresponds to the standard class [[:lower:]], and \u stands for an uppercase character, which corresponds to [[:upper:]].

Standard and nonstandard forms can describe the same set of characters within a given language, but only the standard names carry a guarantee that a pattern reads the same way across tools. The shorthand \d and the class [[:digit:]] are the portable pair. The escape \l depends on the language offering that abbreviation, so a pattern that uses it may not behave the same elsewhere.

Common Mistakes With Counts and Classes

  • Common mistake

    Treating *, +, and ? as interchangeable repetition symbols

    What it looks like

    Using * where a pattern needs at least one occurrence

    Why it fails

    Each symbol carries an exact count. The asterisk is {0,}, the plus is {1,}, and the question mark is {0,1}, so they allow different numbers of occurrences.

    Do this instead

    Rewrite the symbol as its brace form and check the count before choosing it.

  • Common mistake

    Writing the bare class name without the bracket pair

    What it looks like

    Using [:digit:] alone as the whole pattern

    Why it fails

    The class name must be used within a bracket pair, so the bare name is not a complete match instruction.

    Do this instead

    Write [[:digit:]], or the shorthand \d, which stands for that class.

  • Common mistake

    Reading \w as letters only

    What it looks like

    Expecting \w to fail on the digit 7 or the underscore

    Why it fails

    \w matches letters, digits, and the underscore.

    Do this instead

    Keep all three parts of the definition in mind whenever you read \w.

  • Common mistake

    Assuming the brace form {n} allows a range rather than an exact count

  • Common mistake

    Using nonstandard abbreviations in a pattern meant to be portable

    What it looks like

    Using \l where the pattern must run in another tool

    Why it fails

    The source notes that only standard class names are guaranteed to read the same way across tools.

    Do this instead
    Use [[:lower:]] instead.

Practice Matching Counts

EASY

Given the annotated failure AAABBBBBCCC, the annotation tells you that a single letter has the wrong count. Which letter is it, and what does the annotation say about its count?

Hints
  • Each annotation names a single letter whose count is off.
  • Count how many consecutive Bs appear in the string.
MEDIUM

A piece is written as x{1,3}. Using only the notation, list every count of x that the piece allows, and then state whether the string xxxx can match the piece in full.

Hints
  • The notation {1,3} is a bounded range, so the allowed counts run from its minimum to its maximum inclusive.
  • Compare the count in the string with the maximum.

Key Takeaways

  • A pattern piece matches exactly once by default, and a repetition suffix is the only way to change how many times it may occur.
  • The braces {n}, {n,}, and {n,m} state an exact count, an open minimum, and a bounded range, while the symbols *, +, and ? stand for {0,}, {1,}, and {0,1}.
  • A character class name such as [:digit:] must sit inside a bracket pair, giving [[:digit:]], because the bare name is not a complete match instruction.
  • The shorthands \d, \s, and \w stand for [[:digit:]], [[:space:]], and [_[:alnum:]], and their uppercase forms match the complements; prefer standard class names over nonstandard abbreviations for portable patterns.

Related concepts

More concepts starting with C