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.
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?
Reveal 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.
| Notation | Meaning in words | Equivalent brace form |
|---|---|---|
| {n} | exactly n occurrences | not 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.
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.
- 1Read the allowed range
The notation {2,3} is a bounded range. It allows two occurrences of a at minimum and three at maximum.
- 2Count the occurrences in the string
The string aaaa contains four consecutive a characters.
- 3Compare the count with the range
Four is above the maximum of three, so the piece cannot account for the whole string.
No match. The count of a is too high for the notation a{2,3}.
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:]].
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.
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.
Does \w match each of three characters?
Decide whether \w matches the characters q, 7, and an underscore, and whether it matches a hyphen.
- 1List the set
\w matches a letter from a to z, a digit from 0 to 9, or an underscore.
- 2Test the letter q
q is a letter from a to z, so it is in the set.
- 3Test the digit 7
7 is a digit from 0 to 9, so it is in the set even though the name suggests letters.
- 4Test 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.
\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 likeUsing * where a pattern needs at least one occurrence
Why it failsEach 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 insteadRewrite 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 likeUsing [:digit:] alone as the whole pattern
Why it failsThe class name must be used within a bracket pair, so the bare name is not a complete match instruction.
Do this insteadWrite [[:digit:]], or the shorthand \d, which stands for that class.
Common mistake Reading \w as letters only
What it looks likeExpecting \w to fail on the digit 7 or the underscore
Why it fails\w matches letters, digits, and the underscore.
Do this insteadKeep 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 likeUsing \l where the pattern must run in another tool
Why it failsThe source notes that only standard class names are guaranteed to read the same way across tools.
Do this insteadUse [[:lower:]] instead.
Practice Matching Counts
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.
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.