介绍之前,我们先来一个非常简单的使用例子,先见一见
cpp
#include<iostream>
#include<string>
#include<regex>
int main()
{
std::string str = "/number/1234";
std::regex e("/numbers/(\\d+)");
std::smatch matches;
bool ret = std::regex_match(str,matches,e);
if(ret)
for(auto &s:matches)
{
std::cout<<s<<std::endl;
}
return 0;
}
我们本文分为两部分:1.正则表达式的基本语法 2.C++种regex的使用
建议:我们的基础语法不用死记,大家记住常用的就行了
一.正则表达式的基础语法
1)锚点(边界匹配)
锚点不匹配具体字符,而是匹配字符串的位置,用于限定匹配发生的位置。
| 语法 | 含义 | 例子说明 |
|---|---|---|
| ^(常用) | 匹配字符串开头 | ^Hello → 仅匹配以 Hello 开头的字符串 |
$(常用) |
匹配字符串结尾 | World$ → 仅匹配以 World 结尾的字符串 |
\b |
匹配单词边界(单词字符与非单词字符之间) | \bcat\b → 匹配独立单词 cat,不匹配 category |
\B |
匹配非单词边界 | \Bcat\B → 匹配 category 中的 cat,不匹配独立的 cat |
示例:
cpp
#include <iostream>
#include <regex>
#include <string>
using namespace std;
int main() {
string text = "I have a cat and a category";
regex pattern(R"(\bcat\b)"); // 匹配独立的 "cat"
// 搜索所有匹配(用 sregex_iterator)
sregex_iterator it(text.begin(), text.end(), pattern);
sregex_iterator end;
for (; it != end; ++it) {
cout << "匹配到: " << it->str() << endl;
}
// 输出:匹配到: cat(仅匹配独立单词,不匹配 category 中的 cat)
return 0;
}
2)字符类匹配
定义一个字符集合,匹配集合中的任意一个字符。
1. 基础形式(基本都常用)
| 语法 | 含义 | 例子 |
|---|---|---|
[abc] |
匹配 a、b 或 c 中的任意一个 |
gr[ae]y → 匹配 gray 或 grey |
[a-z] |
匹配 a 到 z 之间的任意小写字母 |
[a-z]+ → 匹配连续小写字母 |
[A-Z] |
匹配 A 到 Z 之间的任意大写字母 |
[A-Z]{2} → 匹配连续两个大写字母 |
[0-9] |
匹配 0 到 9 之间的任意数字 |
[0-9]{3} → 匹配连续 3 个数字 |
[a-zA-Z0-9] |
匹配任意字母或数字 | [a-zA-Z0-9]+ → 匹配连续的字母 / 数字 |
2. 排除型字符类(常用)
| 语法 | 含义 | 例子 |
|---|---|---|
[^abc] |
匹配除 a、b、c 外的任意字符 |
[^0-9] → 匹配任意非数字字符 |
[^a-z] |
匹配除小写字母外的任意字符 | [^a-zA-Z] → 匹配任意非字母字符 |
3. 预定义字符类(前面几个我经常用)
注意:这里由于是\d在我们c++进行编写的时候,为了/的完整性我们要//d才能表现出/d,这里我们可以用c++11的原始字符串语法,也就是R"()",比如cout<< R"(\d)"
| 简写 | 含义 | 等价写法 |
|---|---|---|
\d |
匹配任意数字 | [0-9] |
\w |
匹配任意 "单词字符"(字母、数字、下划线) | [a-zA-Z0-9_] |
\s |
匹配任意 "空白字符"(空格、制表符 \t、换行符 \n 等) |
[ \t\n\r\f\v] |
\D |
匹配任意非数字字符 | [^0-9] |
\W |
匹配任意非单词字符 | [^a-zA-Z0-9_] |
\S |
匹配任意非空白字符 | [^ \t\n\r\f\v] |
3)量词
控制前面的字符 / 字符类 / 分组重复出现的次数。
1.基础量词
| 语法 | 含义 | 例子说明 |
|---|---|---|
{n} |
精确重复 n 次 |
\d{4} → 匹配连续 4 个数字(如 2026) |
{n,} |
至少重复 n 次 |
\d{2,} → 匹配连续 2 个或更多数字 |
{n,m} |
重复 n 到 m 次(含 n 和 m) |
\d{2,4} → 匹配连续 2-4 个数字 |
+ |
至少重复 1 次(等价 {1,}) |
\d+ → 匹配 1 个或多个连续数字 |
* |
重复 0 次或多次(等价 {0,}) |
\d* → 匹配 0 个或多个数字(允许空) |
? |
重复 0 次或 1 次(等价 {0,1},表示 "可选") |
colou?r → 匹配 color 或 colour |
2. 贪婪 vs 非贪婪匹配
量词默认是贪婪的 (尽可能多匹配);在量词后加 ? 可变为非贪婪的(尽可能少匹配)。
| 贪婪模式 | 非贪婪模式 | 区别(以字符串 "a123b456b" 为例) |
|---|---|---|
a.*b |
a.*?b |
贪婪:匹配 a123b456b(从第一个 a 到最后一个 b)非贪婪:匹配 a123b(从第一个 a 到第一个 b) |
4)分组与捕获(捕获对象到smatch)
1. 捕获分组
匹配并捕获分组内容,可通过 smatch[n] 在 C++ 中提取。
例如:提取日期中的年、月、日
cpp
#include <iostream>
#include <regex>
#include <string>
using namespace std;
int main() {
string date = "2026-03-27";
regex pattern(R"((\d{4})-(\d{2})-(\d{2}))"); // 3个捕获分组:年、月、日
smatch result;
if (regex_match(date, result, pattern)) {
cout << "完整匹配: " << result[0] << endl; // 2026-03-27(第0组是完整匹配)
cout << "年: " << result[1] << endl; // 2026(第1组)
cout << "月: " << result[2] << endl; // 03(第2组)
cout << "日: " << result[3] << endl; // 27(第3组)
}
return 0;
}
5)选择分支
用 | 表示 "或" 关系,匹配 | 左边或右边的正则表达式,其实简单来说,就是匹配任意一个
例如:
cpp
(GET|HEAD|POST|PUT|DELETE) //捕获任意一个
6)转义字符
如果需要匹配正则中的特殊字符 (如 . ``* ``? ``+ ``( ``) ``[ ``] ``{ } ``^ ``$ ``\ ``| 等),需在前面加 \ 进行转义。
但是这里之前介绍过我们可以用c++11的R"()"----原始字符串的语法,从而不用考虑是否是特殊字符
7)补充:任意字符 .
. 匹配除换行符 \n 外的任意一个字符。
- 例子:
a.c→ 匹配abc、a1c、a!c等(a和c之间有任意一个字符); - 若需匹配包括换行符在内的任意字符,可用
[\s\S](空白 + 非空白,覆盖所有字符)。
8)语法优先级总结(从高到低)
- 转义字符:
\ - 括号:
()、(?:)、[] - 量词:
*、+、?、{n}、{n,}、{n,m} - 锚点:
^、$ - 选择分支:
|
9)C++ 正则使用的核心建议
- 优先用原始字符串
R"()":避免手动转义\,代码更清晰; - 复用
std::regex对象:正则编译开销大,避免在循环中重复构造; - 异常处理 :正则语法错误会抛
std::regex_error,建议用try-catch包裹;
二、C++<regex>介绍
C++ 从 C++11 开始通过标准库 <regex> 提供正则表达式支持,涵盖匹配、搜索、替换和分组捕获等功能。
我们可以平常工作用来匹配对应字符等等,其实竞赛感觉也可以用,因为我记得之前pta的题经常有这种非常恶心的匹配,替换的题目
1、主要类:
| 类名 | 用途说明 |
|---|---|
std::regex |
正则表达式对象,用于存储编译后的正则模式。 |
std::smatch |
匹配结果容器(针对 std::string),存储子匹配(分组)信息。 |
2、核心函数详解
1). std::regex_match:全字符串匹配
函数原型:
cpp
bool regex_match(const std::string& s, const std::regex& re);
bool regex_match(const std::string& s, std::smatch& m, const std::regex& re);
参数:
s:待匹配的字符串。re:std::regex对象(编译后的正则表达式)。m(可选):std::smatch对象,用于存储匹配结果和分组信息。
返回值 :bool,表示是否完全匹配。
2). std::regex_search:子串搜索匹配
在字符串中搜索第一个匹配的子串(无需全匹配)。
函数原型:
cpp
bool regex_search(const std::string& s, const std::regex& re);
bool regex_search(const std::string& s, std::smatch& m, const std::regex& re);
参数 :同 regex_match。
返回值 :bool,表示是否找到匹配。
3). std::regex_replace:替换匹配内容
将字符串中所有匹配的子串替换为指定格式。
函数原型:
cpp
std::string regex_replace(const std::string& s, const std::regex& re, const std::string& fmt);
参数:
s:原字符串。re:std::regex对象。fmt:替换格式字符串,支持$1、$2等引用分组内容。
返回值:替换后的新字符串。
3、常见使用场景代码示例
场景:输入验证(如手机号、邮箱)
cpp
#include <iostream>
#include <regex>
#include <string>
using namespace std;
int main() {
// 验证手机号(1开头,第二位3-9,共11位)
string phone = "13812345678";
regex phone_pattern(R"(^1[3-9]\d{9}$)");
if (regex_match(phone, phone_pattern)) {
cout << "手机号格式正确" << endl;
} else {
cout << "手机号格式错误" << endl;
}
// 验证邮箱(简单示例,非严格RFC标准)
string email = "test@example.com";
regex email_pattern(R"(^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$)");
if (regex_match(email, email_pattern)) {
cout << "邮箱格式正确" << endl;
}
return 0;
}