您好,我是昊天,C++程序员,多年的音视频开发经验,熟悉Qt、FFmpeg、OpenGL。如果你对这些感兴趣,欢迎关注我的公众号 由于AI IDE的普及,愈发感觉基础的重要性,后续我会用一系列的文章,讲解C++的基础知识点,本文是第一篇。
正则表达式(Regular Expression,简称 Regex)是一种用于描述字符串匹配规则的工具。常用来查找、提取、验证、替换字符串中符合特定模式的内容,例如:
应用场景 | 举例说明 |
---|---|
数据校验 | 检查手机号、邮箱、身份证号等格式是否正确 |
文本提取 | 从 HTML 中提取所有链接、从日志中提取 IP |
批量替换 | 批量替换文件中的注释、变量名或标签 |
搜索分析 | 检索特定字段、关键词或格式,如日期、时间等 |
清洗数据 | 去除多余空格、非法字符、HTML 标签等 |
之前使用Qt框架的正则表达式,但是书写底层库时,不想依赖Qt框架,毕竟Qt太重了。
好在 C++ 标准库引入了正则表达式,C++ 原生支持了。
从 C++11 开始,标准库 <regex>
正式引入正则表达式支持。该模块功能强大,覆盖了正则的构造、匹配、搜索、提取、替换等全流程操作。核心模块如下:
类/函数 | 作用 |
---|---|
std::regex | 构造正则表达式对象 |
std::regex_match | 匹配整个字符串 |
std::regex_search | 匹配字符串中的部分 |
std::regex_replace | 替换匹配内容 |
std::smatch / std::cmatch | 用于保存匹配结果(分别用于 std::string 和 C 风格字符串) |
std::sregex_iterator / std::cregex_iterator | 用于遍历字符串中所有匹配正则表达式的部分 |
std::sregex_token_iterator / std::cregex_token_iterator | 用于遍历字符串中所有不匹配正则表达式的部分 |
为了清晰明确的展示C++中的正则表达式的用法,下面分别展示5种常见的用法。
std::regex_match
函数用于检查整个字符串是否与正则表达式匹配。如果匹配成功,则返回 true
,否则返回 false
。
#include <iostream>
#include <regex>
int main() {
std::string input = "2025-07-15";
std::regex date_pattern(R"(\d{4}-\d{2}-\d{2})");
if (std::regex_match(input, date_pattern)) {
std::cout << "合法日期格式" << std::endl;
} else {
std::cout << "非法格式" << std::endl;
}
}
std::regex_search
函数用于在字符串中搜索第一个与正则表达式匹配的部分。如果找到匹配项,则返回 true
,否则返回 false
。
#include <iostream>
#include <regex>
int main() {
std::string text = "我的邮箱是 user@example.com,请联系我。";
std::regex email_pattern(R"(\b\w+@\w+\.\w+\b)");
std::smatch match;
if (std::regex_search(text, match, email_pattern)) {
std::cout << "发现邮箱:" << match[0] << std::endl;
}
}
std::regex_replace
函数用于将字符串中所有匹配正则表达式的部分替换为指定的字符串。
#include <iostream>
#include <regex>
int main() {
std::string text = "访问我们的网站:http://example.com";
std::regex url_pattern(R"(http://\S+)");
std::string replaced = std::regex_replace(text, url_pattern, "[链接已屏蔽]");
std::cout << replaced << std::endl;
}
std::sregex_iterator
类用于遍历字符串中所有匹配正则表达式的部分,返回一个迭代器,可以像普通迭代器一样使用。
#include <iostream>
#include <regex>
int main() {
std::string text = "联系人: tom@example.com, jerry@mail.com";
std::regex email_pattern(R"(\b\w+@\w+\.\w+\b)");
auto begin = std::sregex_iterator(text.begin(), text.end(), email_pattern);
auto end = std::sregex_iterator();
for (auto it = begin; it != end; ++it) {
std::cout << "发现邮箱:" << it->str() << std::endl;
}
}
std::smatch
类用于保存匹配结果,支持通过索引或名称访问匹配组。
#include <iostream>
#include <regex>
int main() {
std::string input = "电话:+86-13800138000";
std::regex phone_pattern(R"(\+(\d+)-(\d+))"); // 分组:国家码 和 手机号
std::smatch result;
if (std::regex_search(input, result, phone_pattern)) {
std::cout << "国家码: " << result[1] << ", 手机号: " << result[2] << std::endl;
}
}
注意点 | 建议说明 |
---|---|
性能问题 | 对长文本或复杂表达式应避免频繁创建 std::regex,应复用同一个对象 |
转义字符 | 尽量使用原始字符串字面量:R"(pattern)" 避免 \\ 混乱 |
匹配失败行为 | regex_match 要求整个字符串匹配,regex_search 只要匹配一部分就行 |
某些平台兼容性差 | GCC 4.8 及更早版本对 <regex> 支持不完善,推荐使用 GCC 4.9+、MSVC 2013+ |
正则语法不完全一致 | C++11 正则库基于 ECMAScript 标准语法,但不完全等同 JS 正则的功能,例如不支持命名组、非贪婪量词略有区别。 |
Unicode 字符处理较弱 | 对中文字符建议结合 wstring 或使用外部库(如 ICU)处理更稳妥 |
正则语法并不是本文的重点,但是为了便于理解,同时为了文章的完整度,接下来将简单介绍正则语法ECMA标准。
符号 | 作用 |
---|---|
. | 匹配除换行符以外的任意字符 |
^ | 匹配字符串的开头 |
$ | 匹配字符串的结尾 |
* | 匹配前面的子表达式零次或多次 |
符号 | 作用 |
---|---|
[abc] | 匹配字符 a、b 或 c |
[^abc] | 匹配除 a、b、c 之外的任意字符 |
符号 | 作用 |
---|---|
\d | 匹配数字字符(等价于 [0-9]) |
\D | 匹配非数字字符(等价于 [^0-9]) |
符号 | 作用 |
---|---|
+ | 匹配前面的子表达式一次或多次 |
? | 匹配前面的子表达式零次或一次 |
{n} | 匹配前面的子表达式恰好 n 次 |
符号 | 作用 |
---|---|
(pattern) | 匹配并捕获 pattern |
\1、\2 | 分别表示第一个和第二个捕获组 |
符号 | 作用 |
---|---|
(?=pattern) | 正向先行断言,匹配后面是 pattern 的位置 |
(?!pattern) | 负向先行断言,匹配后面不是 pattern 的位置 |
(?<=pattern) | 正向后行断言,匹配前面是 pattern 的位置 |
(?<!pattern) | 负向后行断言,匹配前面不是 pattern 的位置 |
<regex>
,提供了完整的正则工具链。