拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

正则表达式c++内容汇集

正则表达式c++内容汇集

std::regex ECMAScript 语法完整参考

C++ 中std::regex默认使用的正则语法(std::regex_constants::ECMAScript)。
该语法基于ECMAScript 3(ECMA-262 第 3 版),并在此基础上做了少量修改与限制。


目录

  • 一、语法选择与标志
  • 二、核心文法解析
  • 三、元素详解
    • 1. 字符类 Character Classes
    • 2. 量词 Quantifiers
    • 3. 断言 Assertions
    • 4. 分组与反向引用
    • 5. 转义序列
  • 四、括号表达式细节
  • 五、匹配语义
  • 六、替换格式
  • 七、C++ 特有的修改与限制
  • 八、一页速查表
  • 九、参考资料

一、语法选择与标志

#include<regex>usingnamespacestd::regex_constants;

可选语法(syntax_option_type)

取值说明
ECMAScript默认。最接近 JavaScript / .NET 语言的语法
basicPOSIX 基本正则(BRE)
extendedPOSIX 扩展正则(ERE)
awkextended + 更多非打印字符转义
grepbasic + 允许\n分隔分支
egrepextended + 允许\n分隔分支

一次只能指定一种语法。

可叠加的标志

标志作用
icase忽略大小写
nosubs忽略标记匹配(括号内的表达式),不保存替换内容
optimize让匹配更快,代价是构造时间可能更长
collate使用区域敏感的排序序列(如[a-z]按 locale 解释)

可以叠加零个或多个标志。若只指定标志而不指定语法,默认ECMAScript。

std::regexre1(R"(\d+)",std::regex::ECMAScript);std::regexre2(R"(abc)",std::regex::icase|std::regex::ECMAScript);std::regexre3(R"(abc)");// 默认即 ECMAScript

二、核心文法解析

一个正则表达式文法由多个可选项(Alternative)组成,各项之间用析取运算符|分隔。

匹配优先级

|的优先级最低。匹配时引擎会优先尝试匹配左侧的可选项;只有左侧失败,才会尝试右侧。

b|bc// 在 "abcd" 中 search// → 匹配 "b"(左项先成功,不再尝试右项 "bc")

这就是 ECMAScript 的**「首次匹配」**语义,与 POSIX 的「最长匹配」不同。详见 五、匹配语义。

捕获行为

若左侧可选项匹配成功,则右侧可选项中定义的捕获组会产生「空子匹配」(empty submatches)。

(a)|(b)// 匹配 "a" 时:// 捕获组 1 = "a"// 捕获组 2 = 空子匹配(matched = false)

C++ 中通过std::smatch检查:

std::string s="a";std::smatch m;std::regexre(R"((a)|(b))");if(std::regex_search(s,m,re)){m[1].matched;// true, m[1] = "a"m[2].matched;// false ← 空子匹配m[2].str();// ""(但 matched 为 false)}

三、元素详解

1. 字符类 Character Classes

用于匹配一个字符集合中的任意一个字符。

语法含义
[abc]匹配a、b、c中的任意一个字符
[^abc]否定字符类,匹配除a、b、c之外任意字符
[a-z]匹配a到z范围内的任意小写字母
\d、\D匹配数字 / 非数字(C++ 中为区域敏感)
\s、\S匹配空白字符 / 非空白字符(C++ 中为区域敏感)
\w、\W匹配单词字符 / 非单词字符(C++ 中为区域敏感)
[[:alpha:]]POSIX 字符类,匹配字母
[=elt=]等价类,匹配与elt排序等价的字符

dsw 快捷转义与具名类的对应关系:

转义等价具名类默认类
\d[[:d:]][[:digit:]]
\D[^[:d:]][^[:digit:]]
\s[[:s:]][[:space:]]
\S[^[:s:]][^[:space:]]
\w[[:w:]][a-zA-Z0-9_](ASCII)
\W[^[:w:]][^a-zA-Z0-9_](ASCII)

POSIX 具名类([:name:])默认支持:

名称含义
alnum大小写字母 + 数字
alpha大小写字母
blank空格或制表符
cntrl控制字符
digit数字
graph字母 + 数字 + 标点
lower/upper小写 / 大写字母
print字母 + 数字 + 标点 + 空格
punct标点
space空格
xdigit十六进制数字
d/s/w分别同digit/space/alnum

⚠️\w默认只认 ASCII 字符,匹配中文等 Unicode 字母需要自己写字符类。

通配符.

.// 匹配目标序列中除换行(\n)以外的任意字符

普通字符(需转义的特殊字符)

ECMAScript 中有特殊含义的字符固定为这 13 个:

^ $ \ . * + ? ( ) [ ] { } |

标识转义(Identity Escape)

反斜杠 + 单个字符,匹配该字符本身,用于去掉特殊含义。

a*// 匹配 "aaa"a\*// 匹配字面量 "a*",不匹配 "aaa"

各语法允许标识转义的字符集不同:

语法允许标识转义的字符
basic/grep( ) { } . [ \ * ^ $
extended/egrep( ) { . [ \ * ^ $ + ? |
awk上述 +"/
ECMAScript除「可构成标识符的字符」外全部—— 字母、数字、$、_、Unicode 转义序列不能被标识转义

2. 量词 Quantifiers

用于指定前一个元素重复的次数。

语法含义
*匹配零次或多次(等价{0,})
+匹配一次或多次(等价{1,})
?匹配零次或一次(等价{0,1})
{n}恰好匹配 n 次
{n,}至少匹配 n 次
{n,m}匹配 n 到 m 次

贪婪与非贪婪

默认情况下量词是贪婪的 —— 会尽可能多地匹配字符。

(a+)(a*b)// 目标 "aaab"// 贪婪: 组1="aaa", 组2="b"

在量词后加?可变为非贪婪模式:

(a+?)(a*b)// 目标 "aaab"// 非贪婪:组1="a", 组2="aab"

可用于量词的元素:除(?=、(?!、^、$之外的所有元素。

以下示例均按整串匹配(std::regex_match)语义理解。

a{2,3}// 匹配 "aa" / "aaa",不匹配 "a" / "aaaa"a{2}// 只匹配 "aa"a{2,}// 匹配 "aa" 及以上ab+// 整串匹配 "abb",不匹配 "abab"(ab)+// 不匹配 "abb",匹配 "abab"

⚠️注意区分regex_match与regex_search。
regex_search只要求存在子序列匹配即可,因此用regex_search时
ab+能在"abab"中找到"ab",(ab)+能在"abb"中找到"ab"。
详见 五、匹配语义。


3. 断言 Assertions

断言不消耗字符,只用于检查某个条件是否成立(零宽匹配)。

语法含义
^匹配输入的开头
$匹配输入的结尾
\b匹配单词边界
(?=...)正向先行断言:要求右侧能匹配...
(?!...)负向先行断言:要求右侧不能匹配...
(?<=...)正向后行断言:要求左侧能匹配...
(?<!...)负向后行断言:要求左侧不能匹配...

⚠️后行断言((?<=)/(?<!))在 C++ 标准中不属于 ECMAScript 文法,std::regex不支持。
上表列出是为了与 JavaScript 对照 —— 现代 JS 已支持后行断言,C++ 没有跟进。

单词边界出现的四种情况:

  1. 当前字符在序列开头,且是单词字符(A-Za-z0-9_)
  2. 当前位置越过序列结尾,且最后一个字符是单词字符
  3. 当前字符是单词字符,前一个不是
  4. 当前字符不是单词字符,前一个是

示例:

(?=a)a// 匹配 "a"(?!a)a// 不匹配 "a"a\b.// 匹配 "a~",不匹配 "ab"a\B.// 匹配 "ab",不匹配 "a~"(?!aa)(a*)// 匹配 "a"(组1="a"),不匹配 "aa" / "aaa"(?=aa)(a*)// 匹配 "aaaa",组1="aaaa"

⚠️\b在 ECMAScript 下是单词边界断言,不是退格符。
退格符的写法见 5. 转义序列。


4. 分组与反向引用

语法含义
(...)捕获组,将子模式分组并捕获匹配的文本
(?:...)非捕获组,只分组,不捕获文本
\n反向引用,引用第 n 个捕获组匹配到的文本

捕获组编号:由左括号的出现顺序决定(数到该左括号为止的开括号个数)。

((a+)(b+))(c+)// 组1 = "aabbb"// 组2 = "aa"// 组3 = "bbb"// 组4 = "c"

反向引用的编号解析差异(重要):

语法N 的确定方式上限
basic/grep只取反斜杠后的一位十进制数字N ≤ 9
ECMAScript取反斜杠后连续的所有十进制数字无上限
((a+)(b+))(c+)\3// 匹配 "aabbbcbbb"// \3 引用组3 的内容 "(b+)"(a)\2// 非法(不存在组2)(b(((((((((a))))))))))\10// ECMAScript:\10 = 第 10 个捕获组(最内层那个)// basic: \1 = 第 1 个捕获组,后面的 0 是普通字符 '0'

非捕获组与反向引用:

(?:a)// 合法,但不会产生捕获组(?:a)\1// 非法 —— 不存在第 1 个捕获组

⚠️ C++ 实现限制:捕获组最多 31 个。

分组对量词的影响:

以下按整串匹配理解。

ab+// 整串匹配 "abb"(+ 只作用于 b)(ab)+// 整串匹配 "abab"(+ 作用于整个 "ab")

5. 转义序列

类型形式含义
标识转义\k匹配字符k本身
文件格式转义\f\n\r\t\v换页 / 换行 / 回车 / 水平制表 / 垂直制表
十六进制转义\xhh两位十六进制数表示一个字符
Unicode 转义\uhhhh四位十六进制数表示一个字符
控制字符转义\ck匹配k命名的控制字符(k为a-z/A-Z)

⚠️ ECMAScript 下\a与\b不作文件格式转义:

  • \b是单词边界断言
  • \a不允许(basic/awk里才表示响铃)

示例:

"\ci"// 匹配 "\x09"(Ctrl+I = 0x09)"\x41"// ASCII 下匹配 "a""\u0041"// ASCII 下匹配 "a"\.\.\*\+\?\(\)\[\]\{\}\|\^\$ \\

C++ 中的字符串字面量陷阱:

正则里的\在 C++ 字符串字面量中本身需要转义,否则编译器会先吃掉一层。建议一律用原始字符串字面量(Raw String Literal):

std::regexbad(R"(\d+)");// ✅ 正确:正则收到 \d+std::regexwrong("\\d+");// ✅ 正确但易错std::regexoops("\d+");// ❌ 危险:\d 不是合法转义序列,行为未定义

四、括号表达式细节

[expr]内可包含以下构成的任意组合:

构成形式说明
单个字符abc将该字符加入集合
字符范围ch1-ch2将闭区间[ch1, ch2]内的字符加入集合
字符类[:name:]将具名类中的字符加入集合
等价类[=elt=]将与elt等价的排序元素加入集合
排序符号[.elt.]将排序元素elt加入集合

]的处理 —— ECMAScript 与其他语法的分水岭

// 其他语法:位于开头的 ] 表示自身[]abc]// 匹配 a b c ][^]abc]// 匹配除 a b c ] 外的字符// ECMAScript:必须转义[]a// 匹配 "a"(空括号表达式 + 普通字符 a)[\]abc]// 匹配 a b c ]

^的位置

仅当位于括号表达式开头时表示取反,其他位置表示自身。

[abc]// a 或 b 或 c[^abc]// 非 a b c[a^bc]// a、b、c 或 ^

-的位置

在开头、结尾、或作为某个范围的首尾字符时,表示自身。

[0-7]// { 0,1,2,3,4,5,6,7 }[-0-24]// { -, 0, 1, 2, 4 }[0-2-]// { 0, 1, 2, - }[+--]// { +, ',', - } (ASCII)

范围依赖平台字符编码

[h-k]// ASCII:{ h, i, j, k }// EBCDIC:{ h, i, \x8A, ..., \x90, j, k }(因为 h=0x88, k=0x92)

使用collate标志时,范围内的字符由 locale 的排序规则决定。


五、匹配语义

regex_matchvsregex_search

要求示例
std::regex_match整个正则匹配整个目标序列bcd不匹配"abcd",也不匹配"bcde"
std::regex_search目标中存在子序列匹配即可bcd能匹配"abcd"、"bcde"
bcd 在"abcd"中 search → 匹配后三个字符 bcd 在"bcde"中 search → 匹配前三个字符 bcd 在"bcdbcd"中 search → 匹配前三个字符(最左)

首次匹配 vs 最长匹配

同一位置存在多个匹配时的选择策略:

策略规则
首次匹配(First Match)ECMAScript 使用。取正则匹配过程中先找到的那个
最长匹配(Longest Match)取该位置最长的子序列;长度相同时取先找到的
b|bc 在"abcd"中 search// ECMAScript(首次匹配)→ "b"// 最长匹配 → "bc"

部分匹配 Partial Match

匹配到达目标序列末尾但未到达正则末尾,也算成功。

ab 部分匹配"a"✅ ab 部分匹配"ac"❌
  • 部分匹配成功后,向目标追加字符可能导致后续部分匹配失败
  • 部分匹配失败后,向目标追加字符不可能导致后续部分匹配成功
std::regexre("ab");std::smatch m;std::regex_search(s,m,re,std::regex_constants::match_partial);

六、替换格式

std::regex_replace的替换串中可使用以下格式:

ECMAScript 规则sed 规则替换为
$&&整个匹配[match[0].first, match[0].second)
$$—字面量$
—\&字面量&
$`—匹配之前的文本(前缀)
$'—匹配之后的文本(后缀)
$n\n第 n 个捕获组(n = 0–9)
—\\n字面量\
$nn—第 nn 个捕获组(nn = 10–99)
std::string s="2026-09-18";std::regexre(R"((\d{4})-(\d{2})-(\d{2}))");// 换成 年/月/日std::string out=std::regex_replace(s,re,"$1/$2/$3");// "2026/09/18"

七、C++ 特有的修改与限制

C++ 的 ECMAScript 文法基于 ECMAScript 3,并做了以下修改:

1. POSIX 类型扩展

在字符类(character class)内部引入了对本地环境(locale)的 POSIX 类型扩展。

[[:alpha:]]// 匹配字母(POSIX 具名类)[[:digit:]]// 匹配数字[[:space:]]// 匹配空白

2. 区域敏感

\d、\s、\w等字符类在 C++ 中是区域敏感(locale-sensitive)的。

也就是说,它们的行为可能随std::locale设置而改变,与 JavaScript 的固定 ASCII 行为不同。

3. 不支持的特性

C++ 标准库的std::regex不支持以下语法:

不支持的语法说明JS 是否支持
(?<=...)后行断言✅ 现代 JS 支持
(?<!...)否定后行断言✅ 现代 JS 支持
(?<name>...)具名捕获组✅
\k<name>具名反向引用✅
\p{...}Unicode 属性类✅
\Q...\E引用块❌(PCRE 支持)
x++/x*+占有量词❌(PCRE/Java 支持)
(?(cond)...)条件表达式❌(PCRE 支持)

4. 语法选项互斥

ECMAScript是默认文法;在basic、extended、awk、grep、egrep等选项中最多只能选择一种。

5. 其他行为差异

项目C++ std::regexJavaScript
^/$只匹配整个序列的开头 / 结尾配合m标志可匹配行首行尾
.不匹配换行\n配合s标志可匹配换行
\w\d\s区域敏感固定 ASCII
捕获组上限31 个无硬性上限
匹配策略首次匹配首次匹配
性能较差(无 DFA 优化)引擎优化较好

⚠️性能提示:std::regex在多数实现中性能显著低于 PCRE / RE2 / JavaScript 引擎。
长文本、复杂正则、循环调用场景建议改用RE2、
PCRE2或 C++17 的std::regex替代品
(如CTRE编译期正则)。


八、一页速查表

锚点 ^ $ 只匹配整个序列的首尾 普通字符 a . . 不匹配换行 字符集合 [...] [^...] ECMAScript 下 ] 必须写成 \] 字符类 \d \D \s \S \w \W 区域敏感 POSIX 类 [[:alpha:]] 等 仅括号表达式内可用 分组 (...) (?:...) 反向引用 \n \nn 无上限;捕获组最多 31 个 先行断言 (?=...) (?!...) 无后行断言 边界 \b \B \b 是边界,不是退格 转义 \xhh \uhhhh \ck \f \n \r \t \v 量词 * + ? {n} {n,} {n,m} 非贪婪 量词后加 ? 分支 a|b 首次匹配,非最长匹配 替换 $& $$ $1 $2 $nn $` $'

常用代码骨架

#include<regex>#include<string>#include<iostream>intmain(){std::string text="订单号 A1234,金额 56.78 元";// 1) 搜索std::regexre(R"([A-Z](\d+))");std::smatch m;if(std::regex_search(text,m,re)){std::cout<<"整个匹配: "<<m.str()<<'\n';// A1234std::cout<<"捕获组 1: "<<m[1].str()<<'\n';// 1234std::cout<<"位置: "<<m.position()<<'\n';}// 2) 完全匹配std::regexre_full(R"(\d{4}-\d{2}-\d{2})");std::cout<<std::boolalpha<<std::regex_match("2026-09-18",re_full)<<'\n';// true// 3) 替换std::regexre_date(R"((\d{4})-(\d{2})-(\d{2}))");std::cout<<std::regex_replace("2026-09-18",re_date,"$1/$2/$3")<<'\n';// 4) 全局遍历std::regexre_num(R"(\d+(\.\d+)?)");autobegin=std::sregex_iterator(text.begin(),text.end(),re_num);autoend=std::sregex_iterator();for(autoit=begin;it!=end;++it){std::cout<<"找到: "<<it->str()<<'\n';}}

九、参考资料

  • ECMA-262 标准(ECMAScript 3 起定义了正则文法)
  • Regular Expressions (C++) — Microsoft Learn(C++ std 库文法对照,最完整的实现级说明)
  • MDN RegExp Guide(JavaScript 侧语法对照)
  • cppreference: std::regex(若可访问)

说明:本参考以 C++ 标准库(std::basic_regex的 ECMAScript 文法)为准。
撰写时 cppreference 全站返回 403(Cloudflare 验证页),故以微软官方 std 库文档为主要依据,
该文档描述的即为同一套std::regexECMAScript 行为,并在实现细节上更细
(捕获组上限、]转义差异、标识转义白名单等)。

返回列表