一、正则表达式基础
正则表达式(Regular Expression,简称Regex/RE)是一种文本模式匹配工具,通过预定义的语法规则描述字符串的特征,用于快速检索、替换、验证符合特定规则的文本(如邮箱、手机号、URL等)。
1. 核心概念
- 模式(Pattern):由正则语法组成的字符串,描述要匹配的文本规则;
- 匹配(Match):检查目标字符串是否符合模式规则,或提取符合规则的子串;
- 元字符 :正则的核心语法,具有特殊含义(如
*、+、|、[]等); - 普通字符:无特殊含义的字符(如字母、数字),匹配自身。
2. 常用正则语法(基础)
| 语法 | 含义 | 示例 |
|---|---|---|
^ |
匹配字符串开头(多行模式下匹配行开头) | ^abc 匹配 "abc123" |
$ |
匹配字符串结尾(多行模式下匹配行结尾) | abc$ 匹配 "123abc" |
. |
匹配任意单个字符(除换行符 \n) |
a.c 匹配 "abc"、"a1c" |
* |
匹配前面的字符/组 0次或多次 | ab*c 匹配 "ac"、"abc"、"abbbc" |
+ |
匹配前面的字符/组 1次或多次 | ab+c 匹配 "abc"、"abbbc"(不匹配"ac") |
? |
匹配前面的字符/组 0次或1次(非贪婪匹配) | ab?c 匹配 "ac"、"abc" |
{n} |
匹配前面的字符/组 恰好n次 | ab{2}c 匹配 "abbc" |
{n,} |
匹配前面的字符/组 至少n次 | ab{2,}c 匹配 "abbc"、"abbbc" |
{n,m} |
匹配前面的字符/组 n到m次 | ab{2,3}c 匹配 "abbc"、"abbbc" |
[] |
字符集:匹配括号内任意一个字符(- 表示范围,^ 表示取反) |
[a-z] 匹配小写字母,[^0-9] 匹配非数字 |
| ` | ` | 或:匹配 ` |
() |
分组:将括号内的模式视为一个整体,可结合量词使用 | (ab)+ 匹配 "ab"、"abab" |
\d |
匹配数字(等价于 [0-9]) |
\d{3} 匹配 3位数字 |
\w |
匹配字母、数字、下划线(等价于 [a-zA-Z0-9_]) |
\w+ 匹配单词 |
\s |
匹配空白字符(空格、制表符、换行符等) | \s+ 匹配多个空格 |
\ |
转义字符:匹配元字符本身(如 \. 匹配 ".",\* 匹配 "*") |
a\.b 匹配 "a.b" |
3. 常用场景示例
- 匹配手机号(11位,以1开头):
^1\d{10}$; - 匹配邮箱:
^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$; - 匹配整数(正负):
^[-+]?\d+$。
二、C++ 正则表达式匹配
C++11 及以上标准提供了 <regex> 库,支持正则表达式操作,核心类和函数如下:
1. 核心组件
| 组件 | 作用 |
|---|---|
std::regex |
存储正则表达式模式(编译后的正则对象) |
std::smatch |
存储字符串匹配结果(针对 std::string) |
std::regex_match |
完全匹配:检查整个字符串是否符合正则模式(返回 bool) |
std::regex_search |
部分匹配:查找字符串中第一个符合正则模式的子串(返回 bool) |
std::regex_replace |
替换:将字符串中符合正则模式的子串替换为指定内容 |
std::sregex_iterator |
迭代器:遍历字符串中所有符合正则模式的子串 |
2. 关键注意事项
- C++ 中反斜杠
\是转义字符,因此正则中的\d需写成\\d(双反斜杠); - 正则模式编译可能抛出异常(如语法错误),建议用
try-catch捕获; - 匹配模式(
std::regex_constants::syntax_option_type):std::regex::ECMAScript:默认模式,兼容 JavaScript 正则语法;std::regex::icase:忽略大小写;std::regex::multiline:多行模式(^/$匹配行开头/结尾)。
三、C++ 正则表达式实战示例
示例1:完全匹配(验证手机号)
cpp
#include <iostream>
#include <string>
#include <regex>
using namespace std;
int main() {
// 正则模式:11位手机号(以1开头,后接10位数字)
// 注意:C++中需用\\d表示\d,而非\d
regex phone_pattern("^1\\d{10}$", regex::ECMAScript);
vector<string> phones = {"13800138000", "1234567890", "138001380001", "abc123456789"};
for (const string& phone : phones) {
bool is_match = regex_match(phone, phone_pattern);
cout << "手机号:" << phone << " → " << (is_match ? "合法" : "非法") << endl;
}
return 0;
}
输出:
手机号:13800138000 → 合法
手机号:1234567890 → 非法
手机号:138001380001 → 非法
手机号:abc123456789 → 非法
示例2:部分匹配(提取字符串中的所有数字)
cpp
#include <iostream>
#include <string>
#include <regex>
#include <iterator>
using namespace std;
int main() {
string text = "小红有10个苹果,小明有20个梨,总共有30个水果。";
// 正则模式:匹配任意数字(\\d+ 匹配1个或多个数字)
regex num_pattern("\\d+");
// 方式1:用 regex_search 找第一个匹配
smatch match_result;
if (regex_search(text, match_result, num_pattern)) {
cout << "第一个数字:" << match_result.str() << endl; // 输出:10
}
// 方式2:用 sregex_iterator 遍历所有匹配
cout << "所有数字:";
sregex_iterator it(text.begin(), text.end(), num_pattern);
sregex_iterator end_it; // 结束迭代器
for (; it != end_it; ++it) {
cout << (*it).str() << " "; // 输出:10 20 30
}
cout << endl;
return 0;
}
输出:
第一个数字:10
所有数字:10 20 30
示例3:替换(将所有空格替换为逗号)
cpp
#include <iostream>
#include <string>
#include <regex>
using namespace std;
int main() {
string text = "hello world! this is c++ regex";
// 正则模式:匹配1个或多个空白字符(\\s+)
regex space_pattern("\\s+");
// 替换:将所有匹配的空格替换为逗号
string result = regex_replace(text, space_pattern, ",");
cout << "替换前:" << text << endl;
cout << "替换后:" << result << endl;
return 0;
}
输出:
替换前:hello world! this is c++ regex
替换后:hello,world!,this,is,c++,regex
示例4:分组匹配(提取邮箱的用户名和域名)
cpp
#include <iostream>
#include <string>
#include <regex>
using namespace std;
int main() {
string email = "test_123@example.com";
// 正则模式:分组匹配用户名和域名(() 表示分组)
regex email_pattern("^([a-zA-Z0-9_-]+)@([a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+)$");
smatch match_result;
if (regex_match(email, match_result, email_pattern)) {
cout << "完整邮箱:" << match_result.str(0) << endl; // 第0组:整个匹配结果
cout << "用户名:" << match_result.str(1) << endl; // 第1组:用户名
cout << "域名:" << match_result.str(2) << endl; // 第2组:域名
}
return 0;
}
输出:
完整邮箱:test_123@example.com
用户名:test_123
域名:example.com
四、常见问题与注意事项
-
转义字符问题 :
C++ 字符串中\是转义符,因此正则中的\d需写成\\d,\.需写成\\.,避免语法错误; -
完全匹配 vs 部分匹配 :
regex_match:要求整个字符串符合模式(如验证手机号、邮箱);regex_search:只需字符串中存在子串符合模式(如提取数字);
-
性能优化 :
频繁使用的正则模式建议提前编译为std::regex对象(避免重复编译); -
异常处理 :
非法正则语法会抛出std::regex_error,建议捕获:cpptry { regex invalid_pattern("^[a-z+"); // 语法错误(缺少]) } catch (const regex_error& e) { cout << "正则语法错误:" << e.what() << endl; }