news 2026/7/30 1:49:47

C++ std::regex 正则表达式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ std::regex 正则表达式

C++ std::regex 正则表达式技术实践文档

1. 文档概述

正则表达式是字符串匹配、检索、替换的核心工具,C++11 正式引入标准库<regex>,原生支持正则语法,无需依赖第三方库。本文基于全套实测代码,系统讲解 C++ 正则三大核心 API:regex_matchregex_searchregex_replace,同时覆盖正则元字符、POSIX 字符类、限定符、分组捕获、字符串格式化等核心知识点。

文档所有案例均可直接编译运行,附带完整运行结果、原理说明与场景适配,适用于 C++ 文本处理、日志解析、数据校验、字符串格式化等开发场景。

2. 核心 API 功能对比

C++ 正则库三大核心函数功能、匹配规则与应用场景差异显著,是开发使用的核心依据,具体对比如下:

核心API匹配规则核心作用典型应用场景
regex_match全串精准匹配,正则必须覆盖整个字符串校验字符串整体格式合法性手机号、邮箱、文件名、账号密码格式校验
regex_search子串模糊匹配,只需字符串局部符合规则检索、提取文本中的目标子串日志关键字提取、颜色码截取、特殊字符筛查
regex_replace基于正则匹配子串,支持分组替换批量替换、格式化、清洗字符串模板占位符替换、手机号格式化、文本脱敏

3. 自定义辅助工具函数

为直观展示正则匹配效果,代码封装了两组通用辅助函数,简化批量测试逻辑:

3.1 search_string + search_by_regex

逐字符遍历目标字符串,筛选并输出所有匹配正则规则的单个字符,适用于字符类规则测试。

3.2 search_by_regexn

基于regex_search实现,快速匹配并输出字符串中第一个符合规则的子串,适用于限定符、分组规则测试。

4. 核心功能案例详解(含运行结果)

4.1 regex_match 全串匹配测试

本案例以固定字符串ccaatt为匹配目标,测试正则元字符、字符类、限定符、首尾锚点等基础语法,严格遵循全串匹配规则。

4.1.1 测试正则规则说明
  • .:匹配除换行符外任意单个字符

  • []:正向字符类,匹配括号内任意字符;[^]:反向字符类,匹配括号外任意字符

  • *、+、?:重复限定符,分别代表0次/多次、1次/多次、0次/1次

  • {n,m}:区间限定符,匹配前面字符 n~m 次

  • ():分组捕获,|:分支选择(或逻辑)

  • ^:行首锚点、$:行尾锚点

4.1.2 完整运行结果
regex_match examples : use regex: ccaatt to match ccaatt [Match!] use regex: cca.tt to match ccaatt [Match!] use regex: cca[a,b,c,d,e]tt to match ccaatt [Match!] use regex: cc[^b,c,d,e]att to match ccaatt [Match!] use regex: ccaa*tt to match ccaatt [Match!] use regex: c+a+t+ to match ccaatt [Match!] use regex: cc?aatt? to match ccaatt [Match!] use regex: ccaat{1,2} to match ccaatt [Match!] use regex: (cat) to match ccaatt [Failed!] use regex: (c(h|d|f)aatt)|(ccaatt) to match ccaatt [Match!] use regex: ^ccaatt to match ccaatt [Match!] use regex: ccaatt$ to match ccaatt [Match!]
4.1.3 核心结论

(cat)匹配失败,原因是regex_match要求正则完全覆盖整串,而非仅包含目标子串,这是区分全串匹配与子串搜索的核心特征。

4.2 regex_search 子串检索测试

regex_search无需匹配整串,只要字符串中存在符合规则的子串即匹配成功,支持单次匹配、循环多次匹配,可获取匹配前缀、后缀及匹配内容。

4.2.1 十六进制颜色码匹配

正则规则:#[a-f]{2}[0-9]{2}[0-9]{2},用于匹配 6 位十六进制颜色值。

运行结果:

regex_search examples : Roses are #ff0000: true violets are #0000ff: true all of my base are belong to you: false matches for 'Roses are #ff0000' Prefix: 'Roses are ' #ff0000 Suffix: '' matches for 'violets are #0000ff' Prefix: 'violets are ' #0000ff Suffix: ''
4.2.2 日志循环检索

遍历日志文本,循环提取所有Speed:后的数值,实现多次匹配。

运行结果:

Speed: 366 Speed: 378 Speed: 400
4.2.3 C风格字符串匹配

使用cmatch适配const char*字符串,输出匹配位置。

运行结果:Found test at position 8

4.3 regex_replace 分组替换测试

regex_replace支持全局替换与分组引用替换,通过$& 引用整体匹配内容,$1/$2/$3引用对应捕获分组内容,是字符串格式化的核心方法。

4.3.1 模板占位符替换

目标文本:{{ @ame }} for brown fox,正则匹配双层大括号占位符。

运行结果:

*2522 for brown fox [{{ @ame }}] for brown fox {{ [@ame] }}
4.3.2 手机号格式化

将不规则手机号(908)555-1800通过分组重排,实现标准化格式化。

运行结果:908,555,1800

4.4 基础匹配场景综合测试

区分regex_searchregex_match的使用差异,验证纯数字字符串校验逻辑。

运行结果:

ab123cdef is all digit: true 123456789 is all digit: true ab123cdef contains digit: 123 abxxx cdef

核心说明:regex_search仅判断是否存在目标子串,regex_match判断整串是否完全符合规则。

5. POSIX 标准字符类详解

C++ 正则支持 POSIX 通用字符类,简化字符匹配规则,替代繁琐的手动字符枚举,是项目高频用法。测试字符串:AaBbCcDdEeFfGg12345 \n!@#$%

正则字符类等效简写匹配范围本次匹配结果
[[:alnum:]]-大小写字母、数字AaBbCcDdEeFfGg12345
[_[:alnum:]]\w字母、数字、下划线AaBbCcDdEeFfGg12345
[^_[:alnum:]]\W非单词字符
!@#$%
[[:digit:]]\d0-9 数字12345
[[:space:]]\s所有空白字符
[[:lower:]]-小写字母aBbCcDdEeFfGg
[[:upper:]]-大写字母AaBbCcDdEeFfGg
[[:punct:]]-标点符号!@#$%
[[:xdigit:]]-十六进制字符AaBbCcDdEeFf12345

6. 正则限定符规则与实测结果

限定符用于控制前序字符/子表达式的匹配次数,是精准匹配的核心语法,结合search_by_regexn实测效果如下:

  • {5}:精准匹配5个字母数字,匹配结果:AaBbC

  • \w{5,}:匹配不少于5个单词字符,匹配结果:AaBbCcDdEeFfGg12345

  • \W{3,5}:匹配3-5个非单词字符,匹配结果:!@#$%

  • .+:匹配所有非空字符,匹配整段测试字符串

  • [[:lower:]]?:匹配0个或1个小写字母,匹配首个小写字母a

7. 关键开发易错点解析

7.1 字符串转义陷阱

C++ 普通字符串中\为转义字符,正则\d、\w必须写为\\d、\\w;推荐使用**R"()"****原始字符串字面量 **,无需手动转义,直接书写原生正则表达式。

7.2 匹配函数误用问题

格式校验必须使用regex_match(全串匹配),仅检索子串使用regex_search,二者不可混用,否则会出现校验逻辑失效问题。

7.3 大小写匹配控制

通过regex::icase标志开启忽略大小写模式,可适配文件后缀、字母编码等不区分大小写的匹配场景。

8. 工程应用场景总结

1.格式校验:基于regex_match实现手机号、邮箱、文件名、账号密码合法性校验;

2.数据提取:基于循环regex_search解析日志、提取数值、特殊编码、关键字;

3.文本处理:基于regex_replace实现模板替换、数据格式化、文本脱敏、特殊符号清洗;

4.字符筛选:基于 POSIX 字符类快速筛选数字、字母、空白字符、标点符号,简化代码逻辑。

9. 文档总结

C++11 提供的std::regex标准库,实现了轻量化、无依赖的正则文本处理能力。核心开发核心是精准区分三大 API 的匹配逻辑:全量校验依托regex_match、局部检索依托regex_search、文本格式化依托regex_replace

正则元字符、POSIX 字符类、次数限定符、分组捕获、原始字符串字面量组合使用,可覆盖绝大多数 C++ 字符串处理业务场景。相较于手动遍历字符判断,正则表达式能大幅精简代码、提升可读性与可维护性,是后端开发、桌面开发、数据处理的必备技术。本文所有案例经过实测验证,可直接落地复用。

// 正则表达式.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。//#include<iostream>#include<regex>#include<iosfwd>usingnamespacestd;staticvoidsearch_string(conststring&str,constregex&reg_ex){// ①for(string::size_type i=0;i<str.size()-1;i++){autosubstr=str.substr(i,1);if(regex_match(substr,reg_ex)){cout<<substr;}}}staticvoidsearch_by_regex(constchar*regex_s,conststring&s){// ②regexreg_ex(regex_s);cout.width(12);// ③cout<<regex_s<<": \"";// ④search_string(s,reg_ex);// ⑤cout<<"\""<<endl;}staticvoidsearch_by_regexn(constchar*regex_s,conststring&s){// ①regexreg_ex(regex_s);smatch match_result;// ②cout.width(14);// ③if(regex_search(s,match_result,reg_ex)){// ④cout<<regex_s<<": \""<<match_result[0]<<"\""<<endl;// ⑤}}#include<iostream>#include<string>#include<regex>usingnamespacestd;voidregex_match_test(){/* std::regex_match: 判断一个正则表达式(参数re)是否匹配整个字符序列str,它主要用于验证文本 注意: 这个正则表达式必须匹配被分析串的全部, 否则返回false;如果整个序列被成功匹配,返回true */string s="ccaatt";vector<regex>regs;vector<string>patterns={"ccaatt","cca.tt",// . 匹配除换行符以外的任意字符。"cca[a,b,c,d,e]tt",// [] 字符类,匹配方括号中包含的任意字符。"cc[^b,c,d,e]att",// [^] 否定字符类。匹配方括号中不包含的任意字符"ccaa*tt",// * 匹配前面的子表达式零次或多次"c+a+t+",// + 匹配前面的子表达式一次或多次"cc?aatt?",// ? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。// 此处说明一下,出现一次或零次的意思可以理解为?前面的字符可出出现可不出现// 注意它与 * 的区别"ccaat{1,2}",//{n,m} 花括号,匹配前面字符至少 n 次,但是不超过 m 次。"(cat)",//(xyz) 字符组,按照确切的顺序匹配字符xyz。"(c(h|d|f)aatt)|(ccaatt)",// | 分支结构,匹配符号之前的字符或后面的字符。// \ 转义符,它可以还原元字符原来的含义,允许你匹配保留字符 [ ] ( ) { } . * + ? ^ $ \ |"^ccaatt",// ^ 匹配行的开始"ccaatt$"// $ 匹配行的结束};for(inti=0;i<patterns.size();i++)regs.push_back(regex(patterns[i]));for(inti=0;i<regs.size();i++){if(regex_match(s,regs[i]))printf("use regex: %25s to match %10s [Match!]\n",patterns[i].c_str(),s.c_str());elseprintf("use regex: %25s to match %10s [Failed!]\n",patterns[i].c_str(),s.c_str());}}voidregex_search_test(){/* std::regex_search: 类似于regex_match,但它不要求整个字符序列完全匹配 可以用regex_search来查找输入中的一个子序列, 注意regex_search匹配成功一个后面的不再匹配 */string lines[]={"Roses are #ff0000","violets are #0000ff","all of my base are belong to you"};regexcolor_regex("#[a-f]{2}""[0-9]{2}""[0-9]{2}");// 简单匹配for(constauto&line:lines){std::cout<<line<<": "<<std::boolalpha<<std::regex_search(line,color_regex)<<'\n';}std::cout<<'\n';// 展示每个匹配中有标记子表达式的内容smatch color_match;for(constauto&line:lines){if(regex_search(line,color_match,color_regex)){cout<<"matches for '"<<line<<"'\n";cout<<"Prefix: '"<<color_match.prefix()<<"'\n";cout<<color_match[0]<<'\n';cout<<"Suffix: '"<<color_match.suffix()<<"\'\n\n";}}// 重复搜索(参阅 std::regex_iterator )std::stringlog(R"( \ Speed: 366 \ Mass: 35 \ Speed: 378 \ Mass: 32 \ Speed: 400 \ Mass: 30)");regexr(R"(Speed:\t\d*)");smatch sm;while(regex_search(log,sm,r)){std::cout<<sm.str()<<'\n';log=sm.suffix();}// C 风格字符串演示cmatch cm;if(regex_search("this is a test",cm,regex("test")))cout<<"\nFound "<<cm[0]<<" at position "<<cm.prefix().length()<<endl;}voidregex_replace_test(){std::string text="{{ @ame }} for brown fox",replace_result;std::regexdouble_brace("(\\{\\{) (.*) (\\}\\})");//regex_replace返回值即为替换后的字符串replace_result=regex_replace(text,double_brace,"*2522");cout<<replace_result<<"\n";//构造存有结果的字符串,[$&]即为用[]将匹配成功部分括起来// $& Inserts the matched substring.cout<<regex_replace(text,double_brace,"[$&]")<<'\n';// $i则输出double_brace中第i个括号匹配到的值cout<<regex_replace(text,double_brace,"$1")<<'\n';cout<<regex_replace(text,double_brace,"[$2]")<<'\n';cout<<regex_replace(text,double_brace,"$3")<<'\n';}intmain(){cout<<"regex_match examples : "<<endl;regex_match_test();cout<<endl<<"regex_search examples : "<<endl;regex_search_test();cout<<endl<<"regex_replace examples : "<<endl<<endl;regex_replace_test();regexr("[[:alpha:]]*\\.(cpp|cxx|cc)",regex::icase);cmatch results;if(regex_search("myfile.cc",results,r))cout<<results.str()<<endl;string phone="(\\()? (\\d{3}) (\\))? ([-. ])? (\\d{3}) ([-. ])? (\\d{4}) ";regexr3e(phone);string number="(908)555-1800";string fmt="$2,$5,$7";//将号码格式改为 ddd.ddd.ddddcout<<regex_replace(number,r3e,fmt)<<endl;string s1="ab123cdef";// ①string s2="123456789";// ②regexex("\\d+");// ③cout<<s1<<" is all digit: "<<regex_search(s1,ex)<<endl;// ④cout<<s2<<" is all digit: "<<regex_match(s2,ex)<<endl;// ⑤smatch match;// ③regex_search(s1,match,ex);// ④cout<<s1<<" contains digit: "<<match[0]<<endl;// ⑤string r111=regex_replace(s1,ex,"xxx");// ③cout<<r111<<endl;// ④//也就是说,R"(content)"中的content是你需要的字符串本身。,输出所有字符string sw=R"("\w\\w\\\w)";cout<<sw<<endl;/*字符类 简写 说明 [[:alnum:]] 字母和数字 [_[:alnum:]] \w 字母,数字以及下划线 [^ _[:alnum:]] \W 非字母,数字以及下划线 [[:digit:]] \d 数字 [^ [:digit:]] \D 非数字 [[:space:]] \s 空白字符 [^ [:space:]] \S 非空白字符 [[:lower:]] 小写字母 [[:upper:]] 大写字母 [[:alpha:]] 任意字母 [[:blank:]] 非换行符的空白字符 [[:cntrl:]] 控制字符 [[:graph:]] 图形字符 [[:print:]] 可打印字符 [[:punct:]] 标点字符 [[:xdigit:]] 十六进制的数字字符*/strings("_AaBbCcDdEeFfGg12345 \t\n!@#$%");// ⑥cout<<s<<endl;search_by_regex("[[:alnum:]]",s);// ⑦search_by_regex("[_[:alnum:]]",s);// ⑧search_by_regex("[^_[:alnum:]]",s);// ⑨search_by_regex("[[:digit:]]",s);// ⑩search_by_regex("[^[:digit:]]",s);// ⑪search_by_regex("[[:space:]]",s);// ⑫search_by_regex("\\S",s);// ⑬search_by_regex("[[:lower:]]",s);// ⑭search_by_regex("[[:upper:]]",s);search_by_regex("[[:alpha:]]",s);// ⑮search_by_regex("[[:blank:]]",s);// ⑯非换行符的空白字符search_by_regex("[[:graph:]]",s);// ⑰search_by_regex("[[:print:]]",s);// ⑱search_by_regex("[[:punct:]]",s);// ⑲search_by_regex("[[:xdigit:]]",s);// ⑳/*字符 说明 { n } 重复n次 { n, } 重复n或更多次 { n,m } 重复[n ~m]次 * 重复0次或多次,等同于{ 0, } + 重复1次或多次,等同于{ 1, } ? 重复0次或1次,等同于{ 0,1 }*/search_by_regexn("[[:alnum:]]{5}",s);// ⑦search_by_regexn("\\w{5,}",s);// ⑧search_by_regexn(R"(\W{3,5})",s);// ⑨search_by_regexn("[[:digit:]]*",s);// ⑩search_by_regexn(".+",s);// ⑪search_by_regexn("[[:lower:]]?",s);// ⑫regexword_regex("[[:alpha:]]+");// ①}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/30 1:48:43

Agent 干活时,终于不用闭嘴了

一个会说话的 Agent&#xff0c;最尴尬的时刻&#xff0c;是它真正开始干活之后。 你让它查一份资料&#xff0c;它很自然地回一句「好&#xff0c;我去看看」。然后工具开始调用&#xff0c;搜索开始转圈&#xff0c;后台开始跑任务&#xff0c;刚才还像个活人的声音突然没了。…

作者头像 李华
网站建设 2026/7/30 1:41:13

微信小程序毕业设计选题指南与30个创新案例

1. 微信小程序毕业设计选题的价值与趋势在当今移动互联网时代&#xff0c;微信小程序已成为连接用户与服务的重要桥梁。根据最新统计&#xff0c;微信小程序日活跃用户已突破4亿&#xff0c;覆盖200多个细分行业。对于计算机相关专业的毕业生而言&#xff0c;选择微信小程序作为…

作者头像 李华
网站建设 2026/7/30 1:41:06

Karpathy重磅论文拆解:从上下文工程到 AI Agent DAG

Karpathy最近丢出了一份 9 页的 PDF 文档&#xff0c;详细阐述了从 Context Engineering&#xff08;上下文工程&#xff09; 到 Agent DAG&#xff08;智能体有向无环图&#xff09; 的演进路径。核心观点极其犀利&#xff1a;“别再只盯着模型本身了&#xff0c;真正的胜负手…

作者头像 李华
网站建设 2026/7/30 1:39:58

Python循环与异常处理的最佳实践与性能优化

1. 循环结构与异常处理的核心逻辑在编程实践中&#xff0c;for循环和异常捕获是两个看似独立却经常需要配合使用的关键机制。for循环作为最基础的流程控制结构&#xff0c;负责对可迭代对象进行遍历操作&#xff1b;而异常捕获则是保证程序健壮性的安全网&#xff0c;两者结合使…

作者头像 李华
网站建设 2026/7/30 1:39:15

空调PTC电辅热原理与使用指南:制热效果与耗电实测

1. 先搞清楚 PTC 电辅热到底解决空调制热的什么问题空调制热时&#xff0c;室外温度越低&#xff0c;传统热泵从室外吸热就越困难。很多人在冬天开空调会发现制热效果差、升温慢&#xff0c;甚至室外机结霜导致频繁停机除霜。PTC 电辅热就是在这种场景下介入的辅助加热方案。它…

作者头像 李华