C++正则表达式
正则表达式Regular Expression简称regex是一种用于描述字符串模式的工具可实现字符串的匹配、搜索、替换、提取等高效操作。C自C11起通过标准库regex头文件正式引入正则表达式支持无需依赖第三方库即可完成复杂的文本处理任务。C标准库的正则表达式体系围绕清晰的结构化模型构建核心是将正则模式封装为std::regex对象通过标准算法如regex_match、regex_search应用于目标字符串匹配结果则通过std::match_results等对象存储支持对完整匹配结果和捕获子表达式的结构化访问。1.正则表达式语法1.1 基础匹配普通字符与转义字符普通字符直接匹配自身如abc匹配字符串abc转义字符需加双反斜杠\\因为C字符串中反斜杠本身是转义字符常用转义字符如下\\d匹配任意数字0-9等价于[0-9] \\D匹配任意非数字等价于[^0-9] \\w匹配任意字母、数字、下划线a-z、A-Z、0-9、_ \\W匹配任意非字母、数字、下划线 \\s匹配任意空白字符空格、制表符、换行符等 \\S匹配任意非空白字符 \\.匹配任意单个字符除换行符\n外 \\|匹配竖线本身竖线在正则中表示“或”需转义。1.2 量词控制匹配次数量词用于指定前面的字符/子表达式匹配的次数常用量词如下优先级从高到低? 匹配0次或1次可选 ab?c匹配ac、abc 匹配1次或多次至少1次 \\d匹配1、123、4567 * 匹配0次或多次任意次数 abc*匹配ab、abc、abcc {n} 匹配恰好n次 \\d{3}匹配123、456仅3位数字 {n,} 匹配至少n次 \\d{2,}匹配12、123、1234 {n,m} 匹配n到m次包含n和m \\d{2,4}匹配12、123、1234注意量词默认是“贪婪匹配”尽可能多匹配在量词后加?可改为“非贪婪匹配”尽可能少匹配例如a.*?匹配最短的以a开头的子串。1.3 捕获组分组匹配与提取用()将正则表达式的一部分括起来称为捕获组可实现“分组匹配”后续可通过match[1]、match[2]等获取分组内容常用于提取复杂字符串中的特定部分。示例正则表达式std::regex re((\\d{4})-(\\d{2})-(\\d{2}));可匹配日期格式如2026-04-17其中match[0]整个日期字符串2026-04-17 match[1]年份2026 match[2]月份04 match[3]日期17。补充非捕获组?:...)——仅用于分组不捕获结果可减少不必要的内存开销例如R(?:abc)匹配多次abc但不单独捕获abc。1.4 边界匹配精准定位用于精准定位匹配的位置避免部分匹配导致的错误常用边界符号-^匹配字符串的开头如^abc匹配以abc开头的字符串-$匹配字符串的结尾如abc$匹配以abc结尾的字符串- \\b单词边界匹配单词的开头或结尾如\\bhello\\b匹配独立的hello单词不匹配helloworld。1.5 逻辑匹配或、非、与-或|匹配多个模式中的一个例如 abc|def 匹配abc或def-非[^...]匹配不在括号内的任意字符例如 [^0-9] 匹配非数字字符- 与默认正则表达式中多个字符/子表达式连续书写即为“与”关系例如abc匹配a且b且c连续出现。2.核心组件2.1 正则表达式对象std::regexstd::regex是C正则表达式的核心类用于封装编译后的正则表达式模式构造时需指定正则字符串和可选的语法/匹配标志。构造方式直接传入正则字符串可搭配语法标志如ECMAScript、icase(不区分大小写)等语法与匹配选项常量说明1Grammar option语法选项指定正则表达式的语法规则一次只能选一种默认是 ECMAScript。- ECMAScript默认选项使用修改过的 ECMAScript 语法与 JavaScript/Java 正则兼容在绝大多数 C 开发场景中最通用-basic是 POSIX BRE基本正则语法老旧不支持 ? {m,n}用于兼容传统 grep 等老旧 POSIX 工具-extended是 POSIX ERE扩展正则支持 ? {m,n}更接近现代语法兼容 grep -E / egrep-awk采用 POSIX awk 工具的正则语法兼容 awk 脚本的写法-grep类似 basic但额外把换行符 \n 作为“或”操作符-egrep类似 extended但把 \n 和制表符 \t 都作为分隔符以兼容 grep -E / egrep 的跨行匹配语义。2Grammar variation语法变体 / 匹配选项修饰匹配行为如忽略大小写、多行模式等可以用 | 与语法选项组合。-icase忽略大小写匹配可以同时匹配 hello/Hello/HELLO 等不同大小写形式-nosubs禁用捕获组匹配结果中不存储子表达式内容适用于只需要判断是否匹配而无需提取分组的场景可以提升性能-optimize优化匹配速度编译正则时会做额外处理耗时更长适合正则会被重复调用的场景如循环中以空间换时间- collate使字符范围 [a-b] 受 locale 影响如非 ASCII 字符的排序规则用于处理本地化字符如中文、法语等- multilineC17 引入多行模式让 ^ 匹配每行开头、$ 匹配每行结尾而非仅匹配整个字符串的首尾用于处理多行文本如日志文件时的逐行匹配需求。#include iostream #include regex #include string using namespace std; int main() { // 邮箱正则表达式 // R 的作用是引入原始字符串字面量让字符串中的反斜杠\、双引号等特殊字符不再被转义 regex email_regex(R(^[A-Za-z0-9._%-][A-Za-z0-9.-]\.[A-Za-z]{2,}$)); //regex email_regex((^[A-Za-z0-9._%-][A-Za-z0-9.-]\\.[A-Za-z]{2,}$)); string email; cout 请输入邮箱地址; cin email; try { smatch match_res; if (regex_match(email, match_res, email_regex)) { cout 邮箱格式合法匹配结果 match_res.str() endl; } else { cout 邮箱格式非法 endl; } } catch (const regex_error e) { cout 正则表达式错误 e.what() endl; } return 0; }2.2 匹配结果存储std::match_results用于存储正则匹配的结果本质是一个包含子匹配sub_match的容器常用的实例化类型有3种根据目标字符串类型选择1std::smatch目标字符串为std::string最常用匹配结果与string对应可通过str()获取字符串形式std::regex_match(const std::string s, std::smatch m, const std::regex e); std::regex_search(const std::string s, std::smatch m, const std::regex e);#include regex #include iostream #include string int main() { std::string text 出生日期: 1990-05-20; std::regex re(R((\d{4})-(\d{2})-(\d{2}))); std::smatch match; if (std::regex_search(text, match, re)) { std::cout 完整匹配: match.str() std::endl; // 1990-05-20 std::cout 年份: match[1].str() std::endl; // 1990 std::cout 月份: match[2].str() std::endl; // 05 std::cout 日期: match[3].str() std::endl; // 20 } return 0; }2std::cmatch目标字符串为const char*适用于C风格字符串使用方式与smatch一致std::regex_match(const char* s, std::cmatch m, const std::regex e); std::regex_search(const char* s, std::cmatch m, const std::regex e);3std::wsmatch目标字符串为std::wstring用于宽字符字符串处理中文等多字节字符场景std::regex_match(const std::wstring s, std::wsmatch m, const std::wregex e); std::regex_search(const std::wstring s, std::wsmatch m, const std::wregex e);核心用法匹配成功后通过下标访问匹配结果match[0]表示整个匹配的字符串match[1]、match[2]...表示第1、2...个捕获组的内容捕获组由正则中的()定义。2.3 核心匹配函数C提供3个核心正则匹配函数分别对应不同的匹配场景需根据需求选择避免混用导致逻辑错误1std::regex_match功能完整匹配——要求目标字符串从头到尾完全符合正则模式一个字符都不能多、不能少常用于字符串格式验证如邮箱、手机号、日期等。// 函数原型 bool regex_match(const std::string s, const std::regex e); bool regex_match(const std::string s, std::smatch m, const std::regex e);#include regex #include iostream int main() { std::regex email_regex(R([A-Za-z0-9._%-][A-Za-z0-9.-]\.[A-Za-z]{2,})); std::string valid_email userexample.com; std::string invalid_email my email is userexample.com; if (std::regex_match(valid_email, email_regex)) { std::cout 邮箱格式正确 std::endl; // 执行 } if (!std::regex_match(invalid_email, email_regex)) { std::cout 邮箱格式不正确 std::endl; // 执行 } // 提取捕获组 std::regex date_regex(R((\d{4})-(\d{2})-(\d{2}))); std::string date 2024-12-25; std::smatch match; if (std::regex_match(date, match, date_regex)) { std::cout 年: match[1] , 月: match[2] , 日: match[3] std::endl; } }2std::regex_search功能部分匹配搜索匹配——在目标字符串中搜索第一个符合正则模式的子串无需整个字符串匹配常用于提取子串、判断字符串中是否包含某类内容如日志中提取IP地址。// 函数原型 bool regex_search(const std::string s, const std::regex e); bool regex_search(const std::string s, std::smatch m, const std::regex e); bool regex_search(const char* first, const char* last, std::cmatch m, const std::regex e);#include regex #include iostream #include string int main() { std::string log 2024-12-25 10:30:45 ERROR: Connection failed from 192.168.1.100; std::regex ip_regex(R(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})); std::smatch match; if (std::regex_search(log, match, ip_regex)) { std::cout 找到IP: match[0] std::endl; // 192.168.1.100 } // 搜索所有匹配配合迭代器 std::string text 苹果15元香蕉8元橙子12元; std::regex price_regex(R(\d元)); auto begin std::sregex_iterator(text.begin(), text.end(), price_regex); auto end std::sregex_iterator(); for (auto it begin; it ! end; it) { std::cout 价格: it-str() std::endl; } // 输出: 15元, 8元, 12元 }注意默认从字符串开头开始搜索可通过传入迭代器指定搜索范围如跳过前导空格若需搜索所有匹配子串需结合std::sregex_iterator使用。3std::regex_replace功能替换匹配——在目标字符串中将所有符合正则模式的子串替换为指定字符串支持替换为捕获组的内容常用于文本清洗如去除空格、替换敏感字符。// 函数原型 std::string regex_replace (const std::string s, const std::regex e, const std::string fmt); std::string regex_replace(const std::string s, const std::regex e, const std::string fmt, std::regex_constants::match_flag_type flags); fmt 在 std::regex_replace 中指定替换格式字符串#include regex #include iostream #include string int main() { // 基础替换去除所有空格 std::string text1 Hello World C; std::regex space_regex(R(\s)); std::string result1 std::regex_replace(text1, space_regex, ); std::cout result1 std::endl; // Hello World C // 使用捕获组格式化电话号码 std::string phone 13812345678; std::regex phone_regex(R((\d{3})(\d{4})(\d{4}))); // $1、$2、$3 是反向引用用于引用正则表达式中捕获组匹配到的内容。 std::string formatted std::regex_replace(phone, phone_regex, $1-$2-$3); std::cout formatted std::endl; // 138-1234-5678 // 敏感信息脱敏 std::string id_card 身份证号11010119900307663X; std::regex id_regex(R((\d{6})\d{8}(\d{3}[0-9X]))); std::string masked std::regex_replace(id_card, id_regex, $1********$2); std::cout masked std::endl; // 身份证号110101********63X // 清洗HTML标签 std::string html pHello bWorld/b/p; std::regex tag_regex(R([^]*)); std::string clean std::regex_replace(html, tag_regex, ); std::cout clean std::endl; // Hello World }2.4 迭代器批量匹配当需要提取目标字符串中所有符合正则模式的子串时需使用正则迭代器常用std::sregex_iterator对应std::string可遍历所有匹配结果。核心逻辑通过迭代器初始化时传入目标字符串和正则对象循环遍历迭代器直到迭代器指向end()每次迭代可获取一个匹配结果smatch对象。// 构造函数指定搜索范围和正则表达式 std::sregex_iterator it(字符串起始迭代器, 字符串结束迭代器, 正则表达式对象); std::sregex_iterator end; // 默认构造的尾后迭代器 // 遍历所有匹配 for (auto it std::sregex_iterator(str.begin(), str.end(), regex); it ! std::sregex_iterator(); it) { std::smatch match *it; // 处理匹配结果 }#include regex #include iostream #include string int main() { std::string text 订单号ORD-001金额299元订单号ORD-002金额450元订单号ORD-003金额128元; std::regex order_regex(R(ORD-(\d{3}))); // 创建正则迭代器 auto begin std::sregex_iterator(text.begin(), text.end(), order_regex); auto end std::sregex_iterator(); // 尾后迭代器 // 遍历所有匹配结果 for (auto it begin; it ! end; it) { std::smatch match *it; std::cout 完整匹配: match.str() std::endl; std::cout 捕获组(订单号后3位): match[1].str() std::endl; std::cout --- std::endl; } return 0; }3. std::regex_error 错误处理详解std::regex_error 是 C 标准库中专门用于报告正则表达式相关异常的类继承自std::runtime_error。#include regex #include iostream class regex_error : public std::runtime_error { public: // 构造函数内部使用用户无法直接构造 explicit regex_error(regex_constants::error_type ecode); // 返回错误码枚举值 regex_constants::error_type code() const noexcept; // 返回错误描述字符串继承自 std::runtime_error const char* what() const noexcept override; };#include regex #include iostream #include string void test_regex(const std::string pattern) { std::cout 测试模式: \ pattern \ std::endl; try { std::regex re(pattern); std::cout ✓ 编译成功 std::endl; } catch (const std::regex_error e) { std::cout ✗ 编译失败: e.what() std::endl; std::cout 错误码: e.code() std::endl; } std::cout std::endl; } int main() { test_regex((unclosed); // 括号不匹配 test_regex(*); // 量词前无内容 test_regex(a{1,2); // 花括号语法错误 test_regex(a{5,2}); // 花括号范围无效 test_regex(\\c); // 无效转义序列 test_regex([[:invalid:]]); // 无效字符类名 test_regex([z-a]); // 字符范围无效 test_regex((valid)\\d); // 正确正则 return 0; }error_brack 括号不匹配 ( 缺少 )、[] 不闭合 error_badrepeat 重复量词前无表达式 *、?、{2} 前面没有可重复的内容 error_brace 花括号 {} 错误 {1,2 缺少 }、{1,a} 非数字 error_brace_range 花括号范围无效 {5,2} 下限大于上限 error_escape 无效的转义序列 \\c无效转义、\\u123不完整 error_content 无效的字符内容 字符类内无效使用如 [a- error_collate 无效的排序元素 [[.xx.]] 无效的排序名 error_ctype 无效的字符类名 [[:invalid:]] error_range 字符范围无效 [z-a] 起始大于结束 error_parsing 解析失败通用错误 语法解析器遇到无法识别的内容 error_space 内存不足 编译后的正则表达式太大超出内存限制 error_stack 栈溢出 正则表达式过于复杂递归深度超限 error_complexity 复杂度超限 匹配操作过于耗时如灾难性回溯 error_collate 无效的排序元素 同上某些实现中重复定义

相关新闻

麒麟系统通用开发环境搭建实战:从零配置到高效开发

麒麟系统通用开发环境搭建实战:从零配置到高效开发

1. 项目概述:为什么要在麒麟系统上搭建开发环境? 最近几年,国产操作系统,特别是以麒麟系列为代表的Linux发行版,在政企、金融、教育等领域的应用越来越广泛。作为一名长期在Linux环境下摸爬滚打的开发者,我…

2026/10/17 21:08:32 阅读更多 →
一些好用的网站(持续跟进)

一些好用的网站(持续跟进)

1、Z-Library,免费下载电子书,热门电影和游戏,还有很多绝版书籍和资源。 链接:Z站图书馆入口 - 官方Z站镜像网址(2025持续更新) 2、lunarora,免费下载电子书 链接:鹿鸣川 - 呦呦鹿鸣处 书卷汇成川 3、读书派&#…

2026/10/23 3:51:29 阅读更多 →
【AI+全栈】 告别切图仔,拥抱Vibe Coding: AI + Cursor 开启多模态全栈新纪元 (1)

【AI+全栈】 告别切图仔,拥抱Vibe Coding: AI + Cursor 开启多模态全栈新纪元 (1)

告别切图仔,拥抱Vibe Coding:MasterGo AI Cursor 开启多模态全栈新纪元从"敲代码"到"描述需求",AI时代的开发范式正在重构引言:软件开发的新范式正在降临 在软件开发的传统叙事中,一个产品从想法…

2026/10/25 17:23:22 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/27 17:33:32 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/27 4:06:49 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/27 7:21:53 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/27 18:20:50 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/27 6:20:47 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/27 4:06:50 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/27 13:55:19 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/27 7:21:50 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/27 19:19:37 阅读更多 →