What Is a Regular Expression (Regexp) and How Do You Use It?

Updated

A regular expression (regexp, or regex) is a small pattern language for describing text. You write a pattern, and a regex engine scans a string to find matches, extract parts of it, or replace what it finds. You use one whenever you need to search, validate, or transform text by shape rather than by exact wording — for example, finding every date in a log file, checking that input looks like an email, or renaming files in bulk. The rest of this article explains the building blocks, walks through a pattern, and covers the mistakes that trip people up.

The core building blocks

Almost every regex is assembled from a handful of constructs. Learn these and you can read most patterns you encounter.

Construct Meaning Example Matches
Literal The character itself cat the text "cat"
Character class Any one character from a set [aeiou] a single vowel
Negated class Any one character not in the set [^0-9] a non-digit
Shorthand class Common predefined sets \d, \w, \s digit, word character, whitespace
Quantifier How many times the previous item repeats a+, a*, a?, a{2,4} one or more, zero or more, optional, 2–4
Anchor Position rather than a character ^, $ start of string/line, end
Group Treat several items as one unit, or capture them (ab)+ "ab" repeated
Alternation Either of two options cat|dog "cat" or "dog"
Dot Any single character (usually except newline) c.t "cat", "cot", "c9t"

Two notes that matter in practice. First, shorthand classes are conventions, not universal law: in most engines \d means [0-9], but some engines extend it to other digit characters, so check your engine if exactness matters. Second, the dot is deliberately broad — c.t also matches "c@t" — which is why people often replace it with a specific class like [a-z].

Reading a pattern step by step

Take this pattern, which is meant to find a simple date:

\b\d{4}-\d{2}-\d{2}\b

Read it left to right:

  • \b — a word boundary, so the match doesn't start in the middle of a longer token.
  • \d{4} — exactly four digits (the year).
  • - — a literal hyphen.
  • \d{2} — exactly two digits (the month).
  • - — another literal hyphen.
  • \d{2} — exactly two digits (the day).
  • \b — a closing word boundary.

Against the text Logged 2024-06-01 at noon, it matches 2024-06-01. Against id 12024-06-01, the leading \b prevents a match starting at the "1" inside the longer number, because there is no boundary between two digits.

That last point is the whole value of anchors and boundaries: they turn a pattern that finds "something that looks like a date" into one that finds "a date as a standalone token."

Where regex shows up in everyday work

  • Search and replace. Editors and IDEs support regex in find-and-replace, so you can rewrite (\w+),\s*(\w+) into $2 $1 to swap "Last, First" into "First Last".
  • Validation. Forms and APIs check that input matches an expected shape, such as a postal code or a phone number format.
  • Log parsing. You pull structured fields out of unstructured lines — timestamps, status codes, request paths — by capturing groups.
  • Data cleanup. You normalize whitespace, strip trailing punctuation, or split a field on a delimiter.
  • Routing and config. Many web frameworks and tools accept regex for URL routes, allow/deny lists, and file filters.

Common pitfalls

Greedy matching. Quantifiers like * and + match as much as possible by default. In <b>one</b> <b>two</b>, the pattern <b>.*</b> matches the entire string, not the first tag. Adding ? (<b>.*?</b>) makes it lazy and stops at the first closing tag.

Unescaped special characters. Characters such as ., *, +, ?, (, ), [, ], {, }, ^, $, |, and \ have meaning. To match them literally, escape them with a backslash — \. matches a literal dot, \$ a literal dollar sign.

Over-broad classes. \w includes letters, digits, and underscore, so \w+ will happily match abc_123. If you only want letters, say [A-Za-z]+.

Catastrophic backtracking. Nested quantifiers over ambiguous patterns can make a match take exponential time on certain inputs. If a pattern hangs on long strings, simplify the nesting or make alternatives more specific.

Assuming one flavor. Engines differ. Lookbehind, named groups, and Unicode property escapes are supported in some languages and not others. A pattern that works in one tool may fail in another.

Test before you ship

Because a pattern's behavior depends on the exact input and the engine, run it against real samples before using it in code or a bulk edit. A visualizer is useful here: it renders the pattern as a diagram so you can see how the pieces nest, and it lets you paste test strings to watch matches highlight in real time. Regex Vis (regex-vis.com) is one such visualizer and editor — note that its page requires JavaScript to run, so enable it before loading the tool. The workflow that avoids most surprises:

  1. Write the pattern and paste a few strings that should match.
  2. Add strings that should not match, especially near-misses like the 12024-06-01 case above.
  3. Check which parts are captured if you plan to extract or replace.
  4. Confirm the same pattern behaves the same way in your target language or tool.

Once the pattern passes those checks, apply it. If it fails later, the failing input is usually the fastest clue to which building block needs tightening.