Concepts / Regular Expression Basics: Character Classes and Anchors

Regular Expression Basics: Character Classes and Anchors

A character class describes a set of possible characters at one position in a pattern.

  • Programming

From Pattern to Printed Line

grep stands for Generalized Regular Expression Parser. It is a command-line program built into Unix, Linux, and macOS systems. You give grep a regular expression pattern and a filename, and it searches the file for matching lines.

The most useful mental model is a line-by-line filter. grep reads the file one line at a time, tests each line against the pattern, prints the entire line when the pattern matches, and skips the line when it does not. The matching lines are printed directly to the terminal as standard output, also called stdout.

grep patternfilenamepattern and fileText fileone line at a timeMatching lineprinted to stdoutNonmatching lineskippedsearchesmatches patterndoes not match
How does a regular expression move from a grep command to file contents, and which lines are passed through as output?

The Basic grep Command

The command has three essential parts: grep is the search program, the quoted pattern is the regular expression to test, and filename identifies the file to search. The pattern is written in quotes in the basic syntax so the shell passes it to grep as one argument.

This command searches mbox-short.txt for lines that start with From:. grep prints every matching line directly to the terminal. It does not print only the matched characters; the output is the complete matching line.

Anchors Control Position

An anchor constrains where a pattern may match instead of describing an ordinary character. The caret, written as ^, is the beginning-of-line anchor. In the pattern ^From:, the caret requires From: to occur at the start of the line. A line containing the same text later in the line does not satisfy that anchored pattern.

^From:must begin at line startFrom: sender@examplematchesReply From:sender@examplecan matchReply From:sender@exampledoes not matchFrom:position not restrictedstarts withrejectsfinds within line
How does a pattern using ^ differ from the same pattern without an anchor, and which parts of a line can match?

What do you think happens?

Suppose a file contains the line Reply From: sender@example. Will grep '^From:' select that line?

  • Yes, because From: appears somewhere in the line

  • No, because From: is not at the beginning

  • Only if the line is the first line in the file

Reveal answer
Answer:

No, because From: is not at the beginning

The caret requires the pattern to begin at the start of the line. The unanchored pattern From: could match the text later in the line, but ^From: cannot.

The same positional idea applies to the dollar sign anchor, $. It constrains a pattern to the end of a line. The important debugging question is therefore not only what characters the pattern contains, but also where those characters are allowed to occur.

Character Classes Choose Characters

A character class describes a set of possible characters at one position in a pattern. For example, [abc] can match one character selected from a, b, or c, while [0-9] can match one character from the range 0 through 9. A negated class uses a caret inside the brackets. The grep class [^ ] means any character that is not a space.

[abc]a, b, or c[0-9]one digit[^ ]any character except space
How does a character class such as [abc] or [0-9] match one character from a set or range of possible characters?

Character classes and anchors solve different problems. A character class controls which character may appear at a position. An anchor controls the position in the line where the surrounding pattern may match. They can be combined when a search needs both restrictions.

Python and grep Syntax

grep and Python both use regular expressions, but they do not support exactly the same features. A key difference is the non-whitespace shorthand \S. Python uses \S to mean any character that is not a space, tab, or newline. grep does not support that shorthand.

GoalPython notationgrep notation
Match a non-whitespace character\S[^ ]
Require text at the beginning of a line^ pattern^ pattern
Search a string or filePython search function works within a string variablegrep searches files on disk

The syntax is not automatically interchangeable. In particular, grep requires the character-class form [^ ] for the non-space case described here.

Debugging Empty or Missing Matches

A grep search that prints nothing has not necessarily failed. It may have correctly skipped every line because the pattern is more restrictive than the file contents. Debugging starts by asking whether the required position, character set, and regular expression syntax actually fit the lines being searched.

  • Common mistake

    Using ^ when the target text may appear later in a line

    What it looks like
    grep '^From:' mbox-short.txt
    Why it fails

    The caret requires From: to occur at the beginning of the line. A line with other text before From: will be skipped.

    Do this instead

    Remove the beginning anchor when the search should find From: anywhere in a line.

  • Common mistake

    Assuming grep supports Python's \S shorthand

    What it looks like

    A pattern copied from Python contains \S.

    Why it fails

    The source describes \S as a Python shorthand that grep does not support.

    Do this instead

    Use [^ ] in grep when the intended match is a character that is not a space.

  • Common mistake

    Making a character class too narrow

    What it looks like

    A class allows only a small set of characters, but the file contains a different character.

    Why it fails

    A character class permits only the characters represented by that class.

    Do this instead

    Broaden the class when the file may legitimately contain additional characters, or inspect the input lines and choose a class that represents them.

Before
grep '^From:' mbox-short.txt

Only lines beginning with From: are eligible

After
grep 'From:' mbox-short.txt

From: may be found elsewhere in a matching line

The before-and-after change does not make one command universally better. It changes the question being asked. The anchored command searches for a line beginning with From:, while the unanchored command allows the text to occur elsewhere. Choose the version that matches the structure of the data.

Practice the Search

EASY

Write a grep command that searches mbox-short.txt for email sender lines beginning with From:. Then explain why the caret is needed if you want only lines whose first characters are From:.

Hints
  • Start with the basic form grep 'pattern' filename.
  • Use the beginning-of-line anchor before From:.
  • The filename is mbox-short.txt.
MEDIUM

A Python pattern uses \S to represent a non-whitespace character. Rewrite that part for grep using the character-class notation described in this article.

Hints
  • grep does not support the Python shorthand \S.
  • Use a negated character class containing a space.

Key Takeaways

  1. 1
    grep searches files line by line and prints every complete line that matches its regular expression.
  2. 2
    The basic command shape is grep 'pattern' filename.
  3. 3
    The caret anchor ^ requires a pattern to begin at the start of a line.
  4. 4
    Character classes such as [abc], [0-9], and [^ ] restrict or describe the character allowed at a position.
  5. 5
    Python and grep do not support exactly the same regular expression features; grep does not support Python's \S shorthand.

At a glance

  • grep applies a regular expression to each line of a file and prints matching lines to stdout.
  • Anchors describe position, while character classes describe allowed or excluded characters.
  • Use ^ when the match must begin at the start of a line.
  • When moving a pattern from Python to grep, check for unsupported syntax such as \S.
  • If grep returns no lines, check whether an anchor, character class, or syntax difference made the pattern too restrictive.

Related concepts

More concepts starting with R