C++: 正则表达式
最后更新:2026-08-26
第41课我们学了文件操作。
现在,我们要学正则表达式——文本处理的"瑞士军刀"。
验证邮箱、提取电话号码、替换文本……正则表达式为这一切提供了简洁的方案。
1. 正则表达式概述
(1) 1.1 什么是正则表达式?
正则表达式(Regex)是一种文本模式描述语言,用于匹配、查找、替换文本。
生活类比:
- 通配符
*→ 匹配任意字符 - 正则表达式 → 更强大的通配符
(2) 1.2 C++正则表达式库
C++11引入了正则表达式支持,在 regex 头文件中。
四个主要函数:
| 函数 | 功能 |
|---|---|
std::regex_match |
完全匹配 |
std::regex_search |
查找 |
std::regex_replace |
替换 |
std::regex_iterator |
迭代查找 |
2. 基本匹配
(1) 2.1 regex_match——完全匹配
示例:验证手机号(难度⭐)
▶ 示例 1:正则表达式应用(难度⭐)
CPP
#include <iostream>
#include <regex>
#include <string>
int main() {
std::string phone = "13812345678";
std::regex pattern("^1[3-9]\\d{9}$"); // 手机号正则
if (std::regex_match(phone, pattern)) {
std::cout << "有效的手机号" << std::endl;
} else {
std::cout << "无效的手机号" << std::endl;
}
return 0;
}
输出:
TEXT
📖 仅展示
有效的手机号
无效的手机号
运行结果:
TEXT
📖 仅展示
有效的手机号
(2) 2.2 正则表达式语法
| 符号 | 说明 | 示例 |
|---|---|---|
. |
任意字符 | a.c 匹配 abc |
^ |
开头 | ^abc 匹配以abc开头 |
$ |
结尾 | abc$ 匹配以abc结尾 |
* |
0次或多次 | a* 匹配 aaa |
+ |
1次或多次 | a+ 匹配 aaa |
? |
0次或1次 | a? 匹配 a 或 `` |
{n} |
恰好n次 | a{3} 匹配 aaa |
[abc] |
字符集 | [abc] 匹配 a 或 b 或 c |
[^abc] |
非字符集 | [^abc] 匹配除abc外的字符 |
\d |
数字 | \d 匹配 0-9 |
\w |
单词字符 | \w 匹配 a-z、A-Z、0-9、_ |
3. 查找和替换
(1) 3.1 regex_search——查找
示例:查找邮箱(难度⭐⭐)
CPP
#include <iostream>
### ▶ 示例 2:正则表达式应用(难度⭐)
#include <regex>
#include <string>
int main() {
std::string text = "联系我:abc@example.com 或 test@gmail.com";
std::regex pattern("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}");
std::smatch match;
if (std::regex_search(text, match, pattern)) {
std::cout << "找到邮箱:" << match[0] << std::endl;
}
return 0;
}
(2) 3.2 regex_replace——替换
示例:隐藏手机号中间四位(难度⭐⭐)
CPP
#include <iostream>
#include <regex>
#include <string>
int main() {
std::string phone = "13812345678";
std::regex pattern("(\\d{3})\\d{4}(\\d{4})");
std::string result = std::regex_replace(phone, pattern, "$1****$2");
std::cout << "隐藏后:" << result << std::endl;
return 0;
}
运行结果:
TEXT
📖 仅展示
隐藏后:138****5678
4. 迭代查找
(1) 4.1 regex_iterator
示例:找出所有邮箱(难度⭐⭐⭐)
CPP
#include <iostream>
#include <regex>
#include <string>
int main() {
std::string text = "联系我:abc@example.com 或 test@gmail.com";
std::regex pattern("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}");
auto begin = std::sregex_iterator(text.begin(), text.end(), pattern);
auto end = std::sregex_iterator();
std::cout << "找到的邮箱:" << std::endl;
for (auto it = begin; it != end; ++it) {
std::cout << it->str() << std::endl;
}
return 0;
}
运行结果:
TEXT
📖 仅展示
找到的邮箱:
abc@example.com
test@gmail.com
5. 分组和捕获
(1) 5.1 分组
用括号 () 创建分组,可以提取子串。
示例:提取日期(难度⭐⭐)
CPP
#include <iostream>
#include <regex>
#include <string>
int main() {
std::string date = "2026-06-28";
std::regex pattern("(\\d{4})-(\\d{2})-(\\d{2})");
std::smatch match;
if (std::regex_match(date, match, pattern)) {
std::cout << "年:" << match[1] << std::endl;
std::cout << "月:" << match[2] << std::endl;
std::cout << "日:" << match[3] << std::endl;
}
return 0;
}
运行结果:
TEXT
📖 仅展示
年:2026
月:06
日:28
6. 常见应用场景
(1) 6.1 验证输入
| 场景 | 正则表达式 |
|---|---|
| 邮箱 | [a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,} |
| 手机号 | ^1[3-9]\d{9}$ |
| 身份证 | ^\d{17}[\dXx]$ |
| IP地址 | ^(\d{1,3}\.){3}\d{1,3}$ |
(2) 6.2 提取信息
示例:从HTML提取链接(难度⭐⭐⭐)
CPP
#include <iostream>
#include <regex>
#include <string>
int main() {
std::string html = "<a href=\"https://example.com\">Example</a>";
std::regex pattern("<a href=\"([^\"]+)\"");
std::smatch match;
if (std::regex_search(html, match, pattern)) {
std::cout << "链接:" << match[1] << std::endl;
}
return 0;
}
▶ 示例 3:验证邮箱格式(难度⭐)
CPP
#include <iostream>
#include <regex>
#include <string>
bool isValidEmail(const std::string& email) {
std::regex pattern(R"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})");
return std::regex_match(email, pattern);
}
int main() {
std::string emails[] = {"test@example.com", "invalid-email", "user.name@domain.org"};
for (const auto& email : emails) {
if (isValidEmail(email)) {
std::cout << email << " -> 有效" << std::endl;
} else {
std::cout << email << " -> 无效" << std::endl;
}
}
return 0;
}
输出:
TEXT
📖 仅展示
-> 有效
-> 无效
❓ 常见问题
Q 正则表达式很慢怎么办?
A - 编译一次,多次使用(
std::regex 构造函数很慢) - 用 std::regex_constants::optimize 标志Q:转义字符太多怎么办? A:用原始字符串字面量(C++11):
CPP
// 难读
std::regex pattern("\\\\d+");
// 好读
std::regex pattern(R"(\d+)");
Q 正则表达式能处理所有文本吗?
A 不能。HTML/XML等用正则解析很复杂,建议用专门的解析器。
📖 小节
| 知识点 | 要点 |
|---|---|
| regex_match | 完全匹配 |
| regex_search | 查找 |
| regex_replace | 替换 |
| regex_iterator | 迭代查找 |
| 分组 | 用 () 提取子串 |
📝 作业
-
**基础题 (Difficulty ⭐):用 std::regex 判断一个字符串是否匹配"纯数字"模式(^\d+$),测试 "123"、"12a3"、"abc"。
-
**进阶题 (Difficulty ⭐⭐):用 regex_search 从一段文本中提取所有邮箱地址(匹配
\w+@\w+\.\w+模式)。 -
挑战题 (Difficulty ⭐⭐⭐):用 regex_replace 实现一个"敏感词过滤"函数——将文本中的指定敏感词替换为 *。支持多个敏感词。
- 正则表达式:模式匹配字符串
- std::regex 构建正则对象
- std::regex_match 完全匹配
- std::regex_search 搜索匹配
- std::regex_replace 替换匹配内容
下一课:多线程基础(#43)