std::regex Quick Reference
C++ regex cheat sheet — std::regex syntax, std::regex_search/match/replace, capture groups, iterators, and performance tips.
Quick Start
cpp
#include <regex>
std::string text = "Hello, World! 2025-01-15";
std::regex date_pattern{R"(\d{4}-\d{2}-\d{2})"};
// Check if pattern exists anywhere in text
bool found = std::regex_search(text, date_pattern);
// Full match (entire string must match)
bool exact = std::regex_match("2025-01-15", date_pattern);
// Extract matches
std::smatch match;
if (std::regex_search(text, match, date_pattern))
std::println("date: {}", match[0].str()); // "2025-01-15"std::regex Construction
cpp
// ECMAScript syntax (default)
std::regex re{R"(\d+\.\d+)"};
// Other syntaxes
std::regex posix{R"([0-9]+)", std::regex::extended};
// Flags (can combine with |)
std::regex ci{R"(hello)", std::regex::icase}; // case-insensitive
std::regex ml{R"(^start)", std::regex::multiline}; // ^ matches line start
std::regex ns{R"(.)", std::regex::ECMAScript}; // . matches \n too with dotall
// Precompile for reuse (expensive to construct — do it once)
const std::regex email_re{
R"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})"
};Pattern Syntax (ECMAScript)
cpp
. — any char except \n
\d — digit [0-9]
\D — non-digit
\w — word char [a-zA-Z0-9_]
\W — non-word
\s — whitespace [ \t\n\r\f\v]
\S — non-whitespace
^ — start of string (or line with multiline)
$ — end of string (or line with multiline)
\b — word boundary
\B — non-word boundary
* — 0 or more (greedy)
+ — 1 or more (greedy)
? — 0 or 1
{n} — exactly n
{n,} — n or more
{n,m} — between n and m
*? +? {n,m}? — lazy (non-greedy)
[abc] — character class
[^abc] — negated class
[a-z] — range
(abc) — capture group
(?:abc) — non-capturing group
a|b — alternation
\1 \2 — backreferences
(?=...) — positive lookahead
(?!...) — negative lookaheadMatching and Searching
cpp
std::string s = "price: $42.50 and $18.99";
std::regex price{R"(\$(\d+)\.(\d{2}))"};
std::smatch m;
// regex_match — whole string must match
std::regex_match("42.50", std::regex{R"(\d+\.\d+)"}); // true
// regex_search — find anywhere in string
if (std::regex_search(s, m, price)) {
std::println("full: {}", m[0].str()); // "$42.50"
std::println("dollars: {}", m[1].str()); // "42"
std::println("cents: {}", m[2].str()); // "50"
std::println("prefix: {}", m.prefix().str()); // "price: "
std::println("suffix: {}", m.suffix().str()); // " and $18.99"
}Capture Groups
cpp
std::string log = "2025-01-15 14:30:22 ERROR Something failed";
std::regex log_re{R"((\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) (\w+) (.+))"};
std::smatch m;
if (std::regex_match(log, m, log_re)) {
std::println("date: {}", m[1].str()); // "2025-01-15"
std::println("time: {}", m[2].str()); // "14:30:22"
std::println("level: {}", m[3].str()); // "ERROR"
std::println("message: {}", m[4].str()); // "Something failed"
}
// Named groups (C++11 ECMAScript doesn't support, but extension in some)
// Use numbered groups insteadIterating All Matches
cpp
std::string text = "foo 42 bar 17 baz 99";
std::regex nums{R"(\d+)"};
// sregex_iterator
for (auto it = std::sregex_iterator(text.begin(), text.end(), nums);
it != std::sregex_iterator{}; ++it) {
std::println("{}", (*it)[0].str()); // 42, 17, 99
}
// sregex_token_iterator (iterate over captures or splits)
std::sregex_token_iterator words_it(text.begin(), text.end(), std::regex{R"(\s+)"}, -1);
std::sregex_token_iterator end;
for (; words_it != end; ++words_it)
std::println("{}", words_it->str()); // "foo", "42", "bar", ...Replace
cpp
std::string html = "<b>Hello</b> <i>World</i>";
// Replace all matches
std::string stripped = std::regex_replace(html, std::regex{R"(<[^>]+>)"}, "");
// "Hello World"
// Replace with capture group reference
std::string s = "John Smith, Jane Doe";
std::string result = std::regex_replace(s, std::regex{R"((\w+) (\w+))"},
"$2, $1");
// "Smith, John, Doe, Jane" (replaces each match)
// Replace only first match
std::string first_only = std::regex_replace(s,
std::regex{R"(\w+ \w+)"},
"PERSON",
std::regex_constants::format_first_only);Split a String
cpp
std::string csv = "Alice,Bob,,Carol,Dave";
std::regex comma{","};
// Split into tokens (-1 means between matches)
std::sregex_token_iterator it(csv.begin(), csv.end(), comma, -1);
std::vector<std::string> parts(it, std::sregex_token_iterator{});
// {"Alice", "Bob", "", "Carol", "Dave"}Error Handling
cpp
try {
std::regex bad_re{"[unclosed"};
} catch (const std::regex_error& e) {
std::println("regex error: {} (code {})", e.what(), (int)e.code());
}Performance Tips
cpp
// 1. Compile the regex ONCE (construction is expensive)
// BAD: recompiles every call
void bad_check(const std::string& s) {
if (std::regex_match(s, std::regex{R"(\d+)"})) { /* ... */ }
}
// GOOD: compile once
void good_check(const std::string& s) {
static const std::regex re{R"(\d+)"};
if (std::regex_match(s, re)) { /* ... */ }
}
// 2. Use raw strings to avoid double-escaping
std::regex path{R"(C:\\Users\\[^\\]+)"}; // without raw: "C:\\\\Users\\\\[^\\\\]+"
// 3. For simple patterns, use string methods instead
s.find("literal") != std::string::npos; // faster than regex for plain strings
s.starts_with("prefix"); // C++20
// 4. Consider alternatives for hot paths
// - re2 library: linear-time, no backtracking
// - PCRE2: full Perl-compatible regex, faster than std::regex
// - std::string_view::find + manual parsing: often fasteststd::regex vs Alternatives
std::regex | re2 | PCRE2 | |
|---|---|---|---|
| C++ standard | Yes (C++11) | External | External |
| Compile time | Slow | Slow | Slow |
| Match time | Slow (backtracking) | Fast (linear) | Fast |
| Features | ECMAScript + others | Limited | Full Perl |
| Lookahead | Yes | No | Yes |
| Named groups | No (ECMAScript, C++11) | No | Yes |
| Recommended | Simple scripts | Production at scale | Full features |