the <regex> library, in outline

<regex> gives you a pattern type (std::regex, compiled once from a pattern string) and three algorithms that use it: std::regex_match, std::regex_search, and std::regex_replace. The default pattern grammar is ECMAScript — the same flavor JavaScript's regex syntax uses — unless you pass a different flag to the std::regex constructor.
Type/functionWhat it's for
std::regexa compiled pattern — construct it once, reuse it
std::smatchmatch results against a std::string — holds the whole match plus any capturing groups
std::regex_matchdoes the entire string match the pattern?
std::regex_searchdoes the pattern match anywhere in the string?
std::regex_replacereturn a new string with every match replaced

regex_match vs. regex_search

The distinction trips people up because both take the same argument shape and both "succeed" or "fail" — but regex_match requires the pattern to account for the whole string (implicitly anchored at both ends), while regex_search is happy to find the pattern as a substring anywhere.

std::regex digits(R"(\d+)");   // raw string literal — avoids escaping the backslash as \\d

std::regex_match("12345", digits);        // true  — the ENTIRE string is digits
std::regex_match("abc123", digits);       // false — "abc" doesn't match, and regex_match needs the whole string

std::regex_search("abc123", digits);      // true — \d+ matches the "123" substring somewhere in the string
            
Note the raw string literal, R"(...)" — without it, a pattern like \d would need to be written "\\d", since \d alone isn't a valid C++ string escape. Raw strings sidestep the double-escaping entirely and are worth defaulting to for any nontrivial pattern.

capturing groups with smatch

Parentheses in the pattern create capturing groups, and std::smatch gives you indexed access to each one after a successful match — index 0 is always the entire match, index 1 is the first parenthesized group, and so on.

std::string line = "2026-08-09: build succeeded";
std::regex entry(R"((\d{4}-\d{2}-\d{2}): (.+))");
std::smatch m;

if (std::regex_match(line, m, entry)) {
  std::cout << "date: "    << m[1] << "\n";   // 2026-08-09
  std::cout << "message: " << m[2] << "\n";   // build succeeded
}
            

regex_replace and backreferences

regex_replace takes a replacement string that can reference captured groups with $1, $2, etc. — useful for reformatting text without manually re-assembling it from smatch pieces.

std::string date = "2026-08-09";
std::regex iso(R"((\d{4})-(\d{2})-(\d{2}))");
std::string us = std::regex_replace(date, iso, "$2/$3/$1");   // "08/09/2026"
            

compile the pattern once

Constructing a std::regex compiles the pattern into an internal representation — that compilation is the expensive part, not the actual matching. If the same pattern is applied to many strings (parsing every line of a log file, say), construct the std::regex once outside the loop and reuse it, rather than rebuilding it from the pattern string on every iteration.

std::regex pattern(R"(\d+)");         // compiled ONCE
for (const auto &line : manyLines) {
  if (std::regex_search(line, pattern)) { /* ... */ }   // reuses the already-compiled pattern
}
            

a small log parser, put together

Capturing groups and regex_replace together, pulling structured fields out of a few log-style lines and reformatting one of them: TopNotchNote/cpp/regex_log_parser_demo.cpp

where to go from here

C++ Fundamentals — std::string_view and std::string, the types regex operates on.
STL Algorithms & Iterators — the rest of the standard library's text/data-processing algorithms.

reference

cppreference — regular expressions library
cppreference — ECMAScript regex grammar