用std::regex_match校验整串格式(如邮箱、日期),用std::regex_search查找子串(如日志中IP、URL参数);二者均需配合std::smatch提取捕获组,且必须检查size或matched字段避免越界。

std::regex_match 和 std::regex_search 选哪个?
匹配整串用 std::regex_match,找子串用 std::regex_search——这是最常混淆的点。比如你有字符串 "id=123&name=alice",想提取 name 后的值,必须用 std::regex_search;若要求整个字符串完全符合模式(如校验邮箱格式),才用 std::regex_match。
两者都返回 bool,但真正提取内容靠 std::smatch。别直接拿 std::regex_iterator 开始遍历,除非你要找全部匹配项。
-
std::regex_match不会填充smatch的子匹配([1]、[2]),除非你传入std::regex_constants::match_default并确保整个串匹配成功 -
std::regex_search才能可靠获取捕获组,哪怕只匹配到第一个就停 - 正则表达式里必须用圆括号
()显式定义捕获组,否则smatch的[1]永远为空
怎么把匹配结果自动转成 std::variant?
std::variant 本身不支持“自动推导类型”,得你自己判断字符串内容再构造。比如你想支持 int、double、std::string 三种类型,就得写分支逻辑:
std::variant<int, double, std::string> parse_value(const std::string& s) {
if (std::regex_match(s, std::regex(R"(^-?\d+$)"))) {
return std::stoi(s);
} else if (std::regex_match(s, std::regex(R"(^-?\d+\.\d+$)"))) {
return std::stod(s);
} else {
return s;
}
}
注意:别用 std::regex_search 去校验纯数字格式,它可能匹配子串(比如 "123abc" 会被当成 "123" 成功),必须用 std::regex_match 加锚点 ^ 和 $。
立即学习“C++免费学习笔记(深入)”;
- 正则模式要加
R"(...)"原始字符串字面量,避免反斜杠被 C++ 字符串解析吃掉 -
std::stoi/std::stod可能抛异常,生产环境得包try/catch - 如果 variant 类型列表很长(比如含
bool、long long),建议抽成查找表或 constexpr 函数,别堆 if-else
捕获组太多时,如何避免手动写 smatch[1], smatch[2]?
手写 smatch[1]、smatch[2] 容易越界或索引错位。更稳的方式是先检查 smatch.size() > N,再取 smatch[N].str():
std::regex re(R"(id=(\d+)&name=(\w+))");
std::smatch m;
if (std::regex_search(input, m, re) && m.size() > 2) {
auto id_str = m[1].str(); // 捕获组1
auto name_str = m[2].str(); // 捕获组2
// 后续转 variant...
}
关键是 m.size() 返回的是匹配总数 + 捕获组数(m[0] 是全匹配,m[1] 起才是捕获组),所以 m.size() > 2 才说明至少有两个捕获组成功。
- 没匹配成功时
m.empty()为 true,但m.size()仍可能是 0 或 1,不能只靠 size 判断是否匹配 -
m[n].matched是更安全的判据,比如m[1].matched确认第 1 组捕获成功 - 如果正则里用了命名捕获(C++11 不支持,C++23 才有),目前只能靠位置索引,别指望
m["name"]
为什么 std::regex 在某些编译器上慢得像卡死?
libstdc++(GCC 默认)的 std::regex 实现是 NFAs 模拟,对复杂正则或长文本可能指数级回溯;libc++(Clang/macOS)稍好,但依然不推荐用于高频匹配。真实项目中,遇到性能问题基本得换库。
- 简单场景(如 URL 参数提取)没问题,但别用
.*开头的模式做全文扫描 - 避免嵌套量词,比如
(a+)+或(.*?)+,容易触发灾难性回溯 - 真要高性能,改用
RE2(Google)或oniguruma,它们用 DFA,保证线性时间 - 如果只是提取固定分隔符字段(如
&、=),直接用std::string_view::find+substr,比正则快一个数量级
正则匹配本身不难,难的是让 variant 构造逻辑跟业务语义对齐——比如空字符串该算 std::string{""} 还是 std::nullopt(这时就得换 std::optional),这点没人替你决定。


















