Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 41

Basic Elisp Regular Expressions

Recommended resources

Introduction

Welcome back! In our last lesson, we explored how to convert data between different types, such as turning the string "123" into the number 123 for calculations, or the string "message" into the symbol message to dynamically reference Elisp code. This ability to transform data is fundamental.

Today, we dive into one of the most powerful text-processing tools in any programmer's arsenal: regular expressions, often shortened to "regex". Your background in writing and editing gives you a deep appreciation for the nuances of text. Regular expressions provide a concise and powerful language to describe and find patterns within that text. Whether you're finding all instances of a specific date format, locating every line that starts with a chapter heading, or transforming quoted dialogue, regex is the tool for the job.

This lesson focuses on the learning outcome: Write basic Elisp regular expressions for pattern matching. We will cover the special syntax used to define these patterns. It's important to note that while the core concepts are universal, Emacs Lisp has its own specific "flavor" of regex syntax, which we will focus on.


1. The Language of Patterns

At its heart, a regular expression is a string of characters that defines a search pattern. Some characters have special meanings (we call them metacharacters), while others are treated literally. To get a practical, Emacs-centric overview of these core components, we'll turn to a video by Protesilaos Stavrou, a prominent figure in the Emacs community.

The video is comprehensive, so we'll watch it in segments, focusing on one concept at a time. As you watch, don't worry about memorizing every detail immediately. The goal is to get a feel for what's possible.

Emacs: basics of regular expressions (regexp)

This video, "Emacs: basics of regular expressions (regexp)", provides an excellent, hands-on demonstration of the core building blocks of regular expressions directly within Emacs.

For now, just watch the section from 00:03:30 to 00:14:51. This covers the most fundamental concepts we will discuss next: line boundaries, the wildcard character, character sets, quantifiers, and grouping. Pay attention to the special characters he uses and what they represent.

Let's break down the key ideas from that video segment.

a. Anchors and Wildcards

These are some of the most common metacharacters.

Character Name Description Example
^ Caret Matches the beginning of a line. ^Once matches "Once upon a time" but not "And once...".
$ Dollar Matches the end of a line. end.$ matches the end of the line "The story must end.".
. Dot Matches any single character except a newline. c.t matches "cat", "cot", and "c_t", but not "ct".

b. Character Sets ([...])

Square brackets allow you to define a set of characters to match.

  • Specific Characters: [aeiou] matches any single lowercase vowel.
  • Ranges: [a-z] matches any lowercase letter. [0-9] matches any digit. You can combine them: [a-zA-Z0-9] matches any letter or digit.
  • Negation: A caret ^ as the first character inside the brackets negates the set. [^0-9] matches any character that is not a digit.

c. Quantifiers (?, +, *)

These operators, called quantifiers or postfix operators, specify how many times the preceding character or group should appear.

Operator Name Description Example
? Question Mark Matches the preceding element zero or one time (makes it optional). colou?r matches both "color" and "colour".
+ Plus Sign Matches the preceding element one or more times. go+al matches "goal" and "gooal" but not "gal".
* Asterisk Matches the preceding element zero or more times. go*al matches "gal", "goal", and "gooal".

d. Grouping and Alternation

These are crucial for building complex patterns.

  • Grouping $...$: Parentheses group parts of a regex together, allowing you to apply a quantifier to the whole group. For example, $ha$+ matches "ha", "haha", "hahaha", and so on. Note the backslashes! This is an Emacs-specific syntax. Many other regex engines just use (...).
  • Alternation \|: The escaped pipe character acts like an "OR". cat\|dog matches "cat" or "dog". When used in a group, like $cat\|dog$, it provides a choice within that part of the pattern. Again, note the backslash.

2. Your Interactive Regex Playground: re-builder

Reading about regex is one thing; using it is another. Emacs comes with a wonderful interactive tool called re-builder (Regular Expression Builder) that lets you type a regex and see it highlight matches in a buffer in real-time. This is the best way to experiment and solidify your understanding.

The following article from "Mastering Emacs" is a perfect introduction to this tool.

re-builder: the Interactive regexp builder

Let's read the article "re-builder: the Interactive regexp builder" to learn how to use this powerful built-in tool.

Read the entire article. Focus on: (1) What re-builder does. (2) The difference between 'read' and 'string' syntax—this is very important. (3) The keybinding C-c TAB to switch syntax and C-c C-w to copy the regex for use in code.

Hands-on Practice

Now it's time to put theory into practice.

  1. Copy the text below into your *scratch* buffer.
  2. With your cursor anywhere in the *scratch* buffer, run M-x re-builder.
  3. A minibuffer will appear at the bottom. This is where you'll type your regular expressions.

Sample Text for Practice:

[2023-10-26] INFO: System startup complete.
[2023-10-26] WARN: Deprecated function 'old-style' called.
[2023-10-27] INFO: User 'anara' logged in.
[2023-10-27] ERROR: Failed to connect to database db-main-01.
[2023-10-28] ERROR: Failed to connect to database db-replica-02a.
This is a comment line that should not match patterns.
[2023-10-28] error: A minor, user-reported error.

Now, try to write a regex for each of the following challenges in the re-builder prompt.

  • Challenge 1: Match only the lines that start with a timestamp (e.g., [2023-10-26]).
  • Challenge 2: Match the words "INFO", "WARN", or "ERROR" but not "error".
  • Challenge 3: Match all variants of "error" (i.e., "ERROR" and "error"). (Hint: re-builder is case-sensitive by default. Look at the article for how to toggle this, or use a character set.)
  • Challenge 4: Match only the database names, which follow the pattern db- and end before the final period (.).
Solutions
  1. ^$$[0-9\-]+$$
    • ^ matches the start of the line.
    • $$ matches a literal [.
    • [0-9\-]+ matches one or more characters that are either a digit (0-9) or a hyphen (-).
    • $$ matches a literal ].
  2. $INFO\|WARN\|ERROR$
    • This uses grouping and alternation to match one of the three specified uppercase words.
  3. [Ee][Rr][Rr][Oo][Rr] or [eE][rR][oO][rR]
    • This uses character sets for each letter to match either its uppercase or lowercase form. Alternatively, in re-builder, you can press C-c C-i to toggle case-insensitivity and just use error.
  4. db-[a-z0-9\-]+
    • db- matches the literal characters.
    • [a-z0-9\-]+ matches the rest of the name, which consists of one or more lowercase letters, numbers, or hyphens.

3. The "Backslash Plague": Regex in Elisp Strings

You've now seen that Emacs regex uses \( and \|. There is one final, crucial detail: writing a regex inside an Elisp string.

In an Elisp string, the backslash \ is also an escape character. To get a literal backslash that the regex engine can see, you must "escape the escape" by typing it twice: \\.

This means a regex that works in re-builder needs to have its backslashes doubled when you put it into a string in your code.

Emacs Lisp Regular Expression Escaping Example
This image illustrates the "backslash plague": to match the word boundary `\b` in an Elisp string, you must write it as `\\b`. The same applies to groups `\\(` and alternations `\\|`.

Let's make this concrete:

Context Regex to match "cat" or "dog"
Interactive (re-builder) $cat|dog$
In an Elisp String `"$cat\

This is arguably the single most common point of confusion when writing Elisp that uses regular expressions. Forgetting to double the backslashes is a frequent source of bugs. A good habit is to always build and test your regex in re-builder first, and then use C-c C-w to copy it. Emacs will automatically convert it to the correct string format with doubled backslashes for you.


Conclusion

In this lesson, we've unpacked the syntax of basic regular expressions in Emacs Lisp. You've moved from the abstract idea of a "pattern" to writing a concrete language that describes it.

Key Takeaways:

  • Regular expressions are a mini-language for describing text patterns.
  • The core building blocks are anchors (^, $), wildcards (.), character sets ([...]), quantifiers (?, +, *), groups ($...$), and alternation (\|).
  • Emacs regex syntax has quirks, most notably requiring backslashes for grouping and alternation (\( and \|).
  • re-builder is an indispensable tool for interactively building and testing your patterns.
  • When writing a regex inside an Elisp string, you must double all backslashes (e.g., \\().

Preview of the Next Lesson

You now know how to write a pattern. In our next lesson, "Use 'string-match' to find patterns and 'match-string' to extract matched groups," we will put these patterns to work. You'll learn how to use Elisp functions to search a string for a pattern and, more excitingly, how to extract the specific pieces of text that your pattern found. This will bring you one step closer to writing functions that can intelligently read and pull information from any text you give them.