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

📅 2026/7/30 1:49:50
C++ std::regex 正则表达式
C std::regex 正则表达式技术实践文档1. 文档概述正则表达式是字符串匹配、检索、替换的核心工具C11 正式引入标准库regex原生支持正则语法无需依赖第三方库。本文基于全套实测代码系统讲解 C 正则三大核心 APIregex_match、regex_search、regex_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: cat 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: 4004.2.3 C风格字符串匹配使用cmatch适配const char*字符串输出匹配位置。运行结果Found test at position 84.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,18004.4 基础匹配场景综合测试区分regex_search与regex_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:]]-十六进制字符AaBbCcDdEeFf123456. 正则限定符规则与实测结果限定符用于控制前序字符/子表达式的匹配次数是精准匹配的核心语法结合search_by_regexn实测效果如下{5}精准匹配5个字母数字匹配结果AaBbC\w{5,}匹配不少于5个单词字符匹配结果AaBbCcDdEeFfGg12345\W{3,5}匹配3-5个非单词字符匹配结果!#$%.匹配所有非空字符匹配整段测试字符串[[:lower:]]?匹配0个或1个小写字母匹配首个小写字母a7. 关键开发易错点解析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. 文档总结C11 提供的std::regex标准库实现了轻量化、无依赖的正则文本处理能力。核心开发核心是精准区分三大 API 的匹配逻辑全量校验依托regex_match、局部检索依托regex_search、文本格式化依托regex_replace。正则元字符、POSIX 字符类、次数限定符、分组捕获、原始字符串字面量组合使用可覆盖绝大多数 C 字符串处理业务场景。相较于手动遍历字符判断正则表达式能大幅精简代码、提升可读性与可维护性是后端开发、桌面开发、数据处理的必备技术。本文所有案例经过实测验证可直接落地复用。// 正则表达式.cpp : 此文件包含 main 函数。程序执行将在此处开始并结束。//#includeiostream#includeregex#includeiosfwdusingnamespacestd;staticvoidsearch_string(conststringstr,constregexreg_ex){// ①for(string::size_type i0;istr.size()-1;i){autosubstrstr.substr(i,1);if(regex_match(substr,reg_ex)){coutsubstr;}}}staticvoidsearch_by_regex(constchar*regex_s,conststrings){// ②regexreg_ex(regex_s);cout.width(12);// ③coutregex_s: \;// ④search_string(s,reg_ex);// ⑤cout\endl;}staticvoidsearch_by_regexn(constchar*regex_s,conststrings){// ①regexreg_ex(regex_s);smatch match_result;// ②cout.width(14);// ③if(regex_search(s,match_result,reg_ex)){// ④coutregex_s: \match_result[0]\endl;// ⑤}}#includeiostream#includestring#includeregexusingnamespacestd;voidregex_match_test(){/* std::regex_match: 判断一个正则表达式(参数re)是否匹配整个字符序列str,它主要用于验证文本 注意: 这个正则表达式必须匹配被分析串的全部 否则返回false;如果整个序列被成功匹配返回true */string sccaatt;vectorregexregs;vectorstringpatterns{ccaatt,cca.tt,// . 匹配除换行符以外的任意字符。cca[a,b,c,d,e]tt,// [] 字符类匹配方括号中包含的任意字符。cc[^b,c,d,e]att,// [^] 否定字符类。匹配方括号中不包含的任意字符ccaa*tt,// * 匹配前面的子表达式零次或多次cat,// 匹配前面的子表达式一次或多次cc?aatt?,// ? 匹配前面的子表达式零次或一次或指明一个非贪婪限定符。// 此处说明一下出现一次或零次的意思可以理解为?前面的字符可出出现可不出现// 注意它与 * 的区别ccaat{1,2},//{n,m} 花括号匹配前面字符至少 n 次但是不超过 m 次。(cat),//(xyz) 字符组按照确切的顺序匹配字符xyz。(c(h|d|f)aatt)|(ccaatt),// | 分支结构匹配符号之前的字符或后面的字符。// \ 转义符它可以还原元字符原来的含义允许你匹配保留字符 [ ] ( ) { } . * ? ^ $ \ |^ccaatt,// ^ 匹配行的开始ccaatt$// $ 匹配行的结束};for(inti0;ipatterns.size();i)regs.push_back(regex(patterns[i]));for(inti0;iregs.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(constautoline:lines){std::coutline: std::boolalphastd::regex_search(line,color_regex)\n;}std::cout\n;// 展示每个匹配中有标记子表达式的内容smatch color_match;for(constautoline:lines){if(regex_search(line,color_match,color_regex)){coutmatches for line\n;coutPrefix: color_match.prefix()\n;coutcolor_match[0]\n;coutSuffix: 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::coutsm.str()\n;logsm.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_resultregex_replace(text,double_brace,*2522);coutreplace_result\n;//构造存有结果的字符串[$]即为用[]将匹配成功部分括起来// $ Inserts the matched substring.coutregex_replace(text,double_brace,[$])\n;// $i则输出double_brace中第i个括号匹配到的值coutregex_replace(text,double_brace,$1)\n;coutregex_replace(text,double_brace,[$2])\n;coutregex_replace(text,double_brace,$3)\n;}intmain(){coutregex_match examples : endl;regex_match_test();coutendlregex_search examples : endl;regex_search_test();coutendlregex_replace examples : endlendl;regex_replace_test();regexr([[:alpha:]]*\\.(cpp|cxx|cc),regex::icase);cmatch results;if(regex_search(myfile.cc,results,r))coutresults.str()endl;string phone\\(? (\\d{3}) (\\))? ([-. ])? (\\d{3}) ([-. ])? (\\d{4}) ;regexr3e(phone);string number(908)555-1800;string fmt$2,$5,$7;//将号码格式改为 ddd.ddd.ddddcoutregex_replace(number,r3e,fmt)endl;string s1ab123cdef;// ①string s2123456789;// ②regexex(\\d);// ③couts1 is all digit: regex_search(s1,ex)endl;// ④couts2 is all digit: regex_match(s2,ex)endl;// ⑤smatch match;// ③regex_search(s1,match,ex);// ④couts1 contains digit: match[0]endl;// ⑤string r111regex_replace(s1,ex,xxx);// ③coutr111endl;// ④//也就是说R(content)中的content是你需要的字符串本身。,输出所有字符string swR(\w\\w\\\w);coutswendl;/*字符类 简写 说明 [[: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!#$%);// ⑥coutsendl;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:]]);// ①}