Card 1 / 5
std::regex_match succeeds only when the entire string fits the pattern β it is anchored at both ends without you writing ^ or $. Write is_hex_color: true for a lowercase hex colour such as #a1b2c3 (a # followed by exactly six hex digits) and false for anything else.
s |
result | why |
|---|---|---|
"#a1b2c3" |
true |
|
"#000000" |
true |
|
"a1b2c3" |
false |
no # |
"#a1b2c" |
false |
five digits |
"#A1B2C3" |
false |
uppercase not in the class |
"#a1b2c3 " |
false |
trailing space β the whole string must match |
Pattern #[0-9a-f]{6}: a literal #, then a character class of hex digits repeated exactly six times. Declare it static const std::regex re(...) inside the function so the pattern is compiled once, not on every call β constructing a std::regex is expensive. Then return std::regex_match(s, re);.
// Return true iff `s` is a lowercase hex colour like "#a1b2c3": a '#' followed
// by exactly six hex digits, and nothing else. std::regex_match succeeds only
// if the WHOLE string matches the pattern.
bool is_hex_color(const std::string& s) {
static const std::regex re("#[0-9a-f]{6}"); // static: compile the pattern once, not per call
return std::regex_match(s, re); // anchored at both ends by definition
}Card 2 / 5
std::regex_search looks for the pattern somewhere in the text β unlike regex_match, which needs the whole string. Write first_number: the first integer appearing anywhere in s, or -1 if there is none.
s |
result |
|---|---|
"order 42 shipped" |
42 |
"room 7, floor 3" |
7 β only the first |
"100 items" |
100 |
"no digits here" |
-1 |
"" |
-1 |
Pattern (\d+): \d is a digit, + one or more, and the parentheses make a capture group. Declare std::smatch m; β a match-results object for std::string β and call std::regex_search(s, m, re). On success m[0] is the whole match and m[1] the first group; std::stoi(m[1].str()) converts it. (Here m[0] and m[1] are the same text β the group becomes essential once the pattern has context around the digits.)
// Return the first integer that appears ANYWHERE in `s`, or -1 if there is
// none. std::regex_search finds a match somewhere in the text (unlike
// regex_match, which needs the whole string). Use a capture group and a
// std::smatch to pull the digits out.
int first_number(const std::string& s) {
static const std::regex re("(\\d+)"); // one capture group: a run of digits
std::smatch m; // receives the match and its groups
if (std::regex_search(s, m, re)) {
return std::stoi(m[1].str()); // m[0] = whole match, m[1] = first group
}
return -1;
}Card 3 / 5
Parentheses in a pattern create capture groups, and after a successful match std::smatch holds each group's text by number. Write parse_date: turn "YYYY-MM-DD" (exactly four, two and two digits) into a Date{year, month, day} β the struct is declared above the editable region β or return std::nullopt when the string does not have that exact shape.
s |
result | why |
|---|---|---|
"2024-03-15" |
Date{2024, 3, 15} |
|
"1999-01-05" |
Date{1999, 1, 5} |
leading zeros parse as numbers |
"2024-3-15" |
nullopt |
month needs two digits |
"2024/03/15" |
nullopt |
wrong separator |
"2024-03-15T10:00" |
nullopt |
trailing text β the whole string must match |
Pattern (\d{4})-(\d{2})-(\d{2}) β three groups, numbered left to right from 1. Use std::regex_match(s, m, re) (whole-string) rather than regex_search, so trailing text is rejected for free. Then Date{std::stoi(m[1]), std::stoi(m[2]), std::stoi(m[3])} β each m[i] is a std::ssub_match that converts to std::string. m[0] is always the entire match.
// Parse an ISO date "YYYY-MM-DD" (exactly 4-2-2 digits, nothing else) into a
// Date. Return std::nullopt if `s` does not have that shape. Use one regex
// with three capture groups; each group's text is in std::smatch m[1..3].
std::optional<Date> parse_date(const std::string& s) {
static const std::regex re("(\\d{4})-(\\d{2})-(\\d{2})"); // three groups: year, month, day
std::smatch m;
if (!std::regex_match(s, m, re)) { // whole-string match, or reject
return std::nullopt;
}
return Date{std::stoi(m[1]), std::stoi(m[2]), std::stoi(m[3])}; // m[i] converts to std::string
}Card 4 / 5
std::regex_search stops at the first hit. To visit every match, use std::sregex_iterator: it walks the string yielding one std::smatch per non-overlapping match. Write words: every maximal run of ASCII letters in s, in order.
s |
result |
|---|---|
"Hello, world!" |
{"Hello", "world"} |
"one2two three" |
{"one", "two", "three"} |
"solo" |
{"solo"} |
"123 456" |
{} |
"" |
{} |
for (std::sregex_iterator it(s.begin(), s.end(), re), end; it != end; ++it) β constructing the iterator with a range and a regex positions it on the first match; a default-constructed std::sregex_iterator is the end marker; ++it advances to the next match. Inside, it->str() is the matched text (the same as (*it)[0]). Pattern [A-Za-z]+. The iterator holds an iterator into s, so s must outlive the loop β never pass a temporary string.
// Return EVERY word in `s` (a "word" is a maximal run of letters a-z / A-Z),
// in order. std::sregex_iterator walks all non-overlapping matches of a
// pattern; dereferencing it yields a std::smatch for the current match.
std::vector<std::string> words(const std::string& s) {
static const std::regex re("[A-Za-z]+");
std::vector<std::string> out;
// Constructing the iterator finds the first match; ++ finds the next.
// A default-constructed sregex_iterator is the end-of-sequence marker.
for (std::sregex_iterator it(s.begin(), s.end(), re), end; it != end; ++it) {
out.push_back(it->str()); // it->str() is the whole match ((*it)[0])
}
return out;
}Card 5 / 5
std::regex_replace rewrites every non-overlapping match of a pattern. Write collapse_spaces: every run of whitespace β spaces, tabs, newlines β becomes a single space.
s |
result |
|---|---|
"a b c" |
"a b c" |
"hello\t\tworld" |
"hello world" |
"line1\n\nline2" |
"line1 line2" |
"no-extra-space" |
unchanged |
" x " |
" x " β edge runs are collapsed, not removed |
Pattern \s+ (\s = any whitespace character, + = one or more) matches each run as one unit, so std::regex_replace(s, re, " ") turns the whole run into one space. As always with std::regex, build it static const so it is compiled once. Trimming the ends would be a second step β this function only collapses.
// Return `s` with every run of whitespace (spaces, tabs, newlines) collapsed
// to a single space. std::regex_replace rewrites every non-overlapping match.
std::string collapse_spaces(const std::string& s) {
static const std::regex re("\\s+"); // \s = any whitespace, + = one or more
return std::regex_replace(s, re, " "); // each run becomes exactly one space
}