命名空间
变体
操作

修改后的 ECMAScript 正则表达式语法

来自 cppreference.com
< cpp‎ | regex

此页面描述了当 std::basic_regex 使用 syntax_option_type 设置为 ECMAScript(默认值)时使用的正则表达式语法。有关其他支持的正则表达式语法的说明,请参阅 syntax_option_type

C++ 中的 ECMAScript 3 正则表达式语法是 ECMA-262 语法,其中包含以下标记为 (C++ 仅) 的修改。

内容

[编辑] 概述

修改后的正则表达式语法 主要基于 ECMAScript RegExp 语法,并在 ClassAtom 下对区域设置进行了 POSIX 类型的扩展。还对相等性检查和数字解析进行了澄清。对于这里的许多示例,您可以在浏览器控制台中尝试以下等效代码

function match(s, re) { return s.match(new RegExp(re)); }

标准中的“规范性引用”指定了 ECMAScript 3。我们在这里链接到 ECMAScript 5.1 规范,因为它是一个与 ECMAScript 3 只有细微变化的版本,并且也有 HTML 版本。有关方言功能的概述,请参阅 MDN 关于 JavaScript RegExp 的指南

[编辑] 备选方案

正则表达式模式是由一个或多个 备选方案 组成,这些 备选方案 由并集运算符 | 分隔(换句话说,并集运算符的优先级最低)。

模式 :

并集

并集 :

备选方案
备选方案 | 并集

模式首先尝试跳过 并集 并匹配左侧 备选方案,然后匹配正则表达式的其余部分(并集之后)。

如果失败,它尝试跳过左侧 备选方案 并匹配右侧 并集(然后匹配正则表达式的其余部分)。

如果左侧 备选方案、右侧 并集 和正则表达式的其余部分都具有选择点,则在转到左侧 备选方案 中的下一个选择之前,会尝试正则表达式其余部分中的所有选择。如果左侧 备选方案 中的选择已耗尽,则会尝试右侧 并集 而不是左侧 备选方案

跳过的 备选方案 中的任何捕获组都会生成空子匹配。

#include <cstddef>
#include <iostream>
#include <regex>
#include <string>
 
void show_matches(const std::string& in, const std::string& re)
{
    std::smatch m;
    std::regex_search(in, m, std::regex(re));
    if (!m.empty())
    {
        std::cout << "input=[" << in << "], regex=[" << re << "]\n  "
                     "prefix=[" << m.prefix() << "]\n  smatch: ";
        for (std::size_t n = 0; n < m.size(); ++n)
            std::cout << "m[" << n << "]=[" << m[n] << "] ";
        std::cout << "\n  suffix=[" << m.suffix() << "]\n";
    }
    else
        std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n";
}
 
int main()
{
    show_matches("abcdef", "abc|def");
    show_matches("abc", "ab|abc"); // left Alternative matched first
 
    // Match of the input against the left Alternative (a) followed
    // by the remained of the regex (c|bc) succeeds, which results
    // in m[1]="a" and m[4]="bc".
    // The skipped Alternatives (ab) and (c) leave their submatches
    // m[3] and m[5] empty.
    show_matches("abc", "((a)|(ab))((c)|(bc))");
}

输出

input=[abcdef], regex=[abc|def]
  prefix=[]
  smatch: m[0]=[abc]
  suffix=[def]
input=[abc], regex=[ab|abc]
  prefix=[]
  smatch: m[0]=[ab]
  suffix=[c]
input=[abc], regex=[((a)|(ab))((c)|(bc))]
  prefix=[]
  smatch: m[0]=[abc] m[1]=[a] m[2]=[a] m[3]=[] m[4]=[bc] m[5]=[] m[6]=[bc]
  suffix=[]

[编辑] 术语

每个 备选方案 都是空的,或者是一系列 术语(术语之间没有分隔符)。

备选方案 :

[空]
备选方案 术语

备选方案 始终匹配并且不会消耗任何输入。

连续的 术语 会尝试同时匹配输入的连续部分。

如果左侧 备选方案、右侧 术语 和正则表达式的其余部分都具有选择点,则在转到右侧 术语 中的下一个选择之前,会尝试正则表达式其余部分中的所有选择,并且在转到左侧 备选方案 中的下一个选择之前,会尝试右侧 术语 中的所有选择。

#include <cstddef>
#include <iostream>
#include <regex>
#include <string>
 
void show_matches(const std::string& in, const std::string& re)
{
    std::smatch m;
    std::regex_search(in, m, std::regex(re));
    if (!m.empty())
    {
        std::cout << "input=[" << in << "], regex=[" << re << "]\n  "
                     "prefix=[" << m.prefix() << "]\n  smatch: ";
        for (std::size_t n = 0; n < m.size(); ++n)
            std::cout << "m[" << n << "]=[" << m[n] << "] ";
        std::cout << "\n  suffix=[" << m.suffix() << "]\n";
    }
    else
        std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n";
}
 
int main()
{
    show_matches("abcdef", ""); // empty regex is a single empty Alternative
    show_matches("abc", "abc|"); // left Alternative matched first
    show_matches("abc", "|abc"); // left Alternative matched first, leaving abc unmatched
}

输出

input=[abcdef], regex=[]
  prefix=[]
  smatch: m[0]=[]
  suffix=[abcdef]
input=[abc], regex=[abc|]
  prefix=[]
  smatch: m[0]=[abc]
  suffix=[]
input=[abc], regex=[|abc]
  prefix=[]
  smatch: m[0]=[]
  suffix=[abc]

[编辑] 量词

  • 每个 术语 都是 断言(见下文)、原子(见下文)或 原子 后面紧跟 量词

术语 :

断言
原子
原子 量词

每个 量词 都是一个 贪婪 量词(仅包含一个 量词前缀)或一个 非贪婪 量词(包含一个 量词前缀 后面紧跟一个问号 ?)。

量词 :

量词前缀
量词前缀 ?

每个 量词前缀 确定两个数字:重复次数的最小值和最大值,如下所示

量词前缀 最小值 最大值
* 无穷大
+ 无穷大
?
{ 十进制数字 } 十进制数字 的值 十进制数字 的值
{ 十进制数字 , } 十进制数字 的值 无穷大
{ 十进制数字 , 十进制数字 } 逗号之前的 十进制数字 的值 逗号之后的 十进制数字 的值

单个 十进制数字 的值是通过在每个数字上调用 std::regex_traits::value(C++ 仅) 获得的。

原子 后面紧跟 量词 表示 原子 被重复了 量词 指定的次数。量词 可以是 非贪婪 的,在这种情况下,原子 模式被重复的次数尽可能少,但仍能匹配正则表达式的剩余部分;也可以是 贪婪 的,在这种情况下,原子 模式被重复的次数尽可能多,但仍能匹配正则表达式的剩余部分。

被重复的是 原子 模式,而不是它匹配的输入,因此 原子 的不同重复可能会匹配输入字符串的不同子字符串。

如果 原子 和正则表达式的剩余部分都具有选择点,则首先尽可能多地(或尽可能少地,如果是非贪婪)匹配 原子。在转到 原子 的最后一次重复中的下一个选择之前,会尝试正则表达式剩余部分中的所有选择。在转到 原子 的倒数第二次(第 n-1 次)重复中的下一个选择之前,会尝试 原子 的最后(第 n 次)重复中的所有选择;此时,可能会有更多或更少的 原子 重复次数可用;在转到 原子 的(第 n-1 次)重复中的下一个选择之前,会先尝试这些重复次数(再次从尽可能少或尽可能多的次数开始),依此类推。

每次 原子 被重复时,它的捕获都会被清除(请参阅下面的 "(z)((a+)?(b+)?(c))*" 示例)。

#include <cstddef>
#include <iostream>
#include <regex>
#include <string>
 
void show_matches(const std::string& in, const std::string& re)
{
    std::smatch m;
    std::regex_search(in, m, std::regex(re));
    if (!m.empty())
    {
        std::cout << "input=[" << in << "], regex=[" << re << "]\n  "
                     "prefix=[" << m.prefix() << "]\n  smatch: ";
        for (std::size_t n = 0; n < m.size(); ++n)
            std::cout << "m[" << n << "]=[" << m[n] << "] ";
        std::cout << "\n  suffix=[" << m.suffix() << "]\n";
    }
    else
        std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n";
}
 
int main()
{
    // greedy match, repeats [a-z] 4 times
    show_matches("abcdefghi", "a[a-z]{2,4}");
    // non-greedy match, repeats [a-z] 2 times
    show_matches("abcdefghi", "a[a-z]{2,4}?");
 
    // Choice point ordering for quantifiers results in a match
    // with two repetitions, first matching the substring "aa",
    // second matching the substring "ba", leaving "ac" not matched
    // ("ba" appears in the capture clause m[1])
    show_matches("aabaac", "(aa|aabaac|ba|b|c)*");
 
    // Choice point ordering for quantifiers makes this regex 
    // calculate the greatest common divisor between 10 and 15
    // (the answer is 5, and it populates m[1] with "aaaaa")
    show_matches("aaaaaaaaaa,aaaaaaaaaaaaaaa", "^(a+)\\1*,\\1+$");
 
    // the substring "bbb" does not appear in the capture clause m[4]
    // because it is cleared when the second repetition of the atom
    // (a+)?(b+)?(c) is matching the substring "ac"
    // NOTE: gcc gets this wrong - it does not correctly clear the
    // matches[4] capture group as required by ECMA-262 21.2.2.5.1,
    // and thus incorrectly captures "bbb" for that group.
    show_matches("zaacbbbcac", "(z)((a+)?(b+)?(c))*");
}

输出

input=[abcdefghi], regex=[a[a-z]{2,4}]
  prefix=[]
  smatch: m[0]=[abcde]
  suffix=[fghi]
input=[abcdefghi], regex=[a[a-z]{2,4}?]
  prefix=[]
  smatch: m[0]=[abc]
  suffix=[defghi]
input=[aabaac], regex=[(aa|aabaac|ba|b|c)*]
  prefix=[]
  smatch: m[0]=[aaba] m[1]=[ba]
  suffix=[ac]
input=[aaaaaaaaaa,aaaaaaaaaaaaaaa], regex=[^(a+)\1*,\1+$]
  prefix=[]
  smatch: m[0]=[aaaaaaaaaa,aaaaaaaaaaaaaaa] m[1]=[aaaaa]
  suffix=[]
input=[zaacbbbcac], regex=[(z)((a+)?(b+)?(c))*]
  prefix=[]
  smatch: m[0]=[zaacbbbcac] m[1]=[z] m[2]=[ac] m[3]=[a] m[4]=[] m[5]=[c] 
  suffix=[]

[编辑] 断言

断言 匹配条件,而不是输入字符串的子字符串。它们永远不会消耗任何来自输入的字符。每个 断言 都是以下之一

断言 :

^
$
\ b
\ B
( ? = 并集 )
( ? ! 并集 )

断言 ^(行首)匹配

1)紧接在 行终止符 字符之后的位置 (这可能不受支持)(直到 C++17) (只有在启用了 std::regex_constants::multiline(C++ 仅) 的情况下才能保证)(自 C++17 起)
2)输入的开头(除非启用了 std::regex_constants::match_not_bol(C++ 仅))。

断言 $(行尾)匹配

1)行终止符 字符的位置 (这可能不受支持)(直到 C++17)(只有在启用了 std::regex_constants::multiline(C++ 仅) 的情况下才能保证)(自 C++17 起)
2)输入的结尾(除非启用了 std::regex_constants::match_not_eol(C++ 仅))。

在上面的两个断言以及下面的原子 . 中,行终止符 是以下四个字符之一:U+000A\n 或换行符)、U+000D\r 或回车符)、U+2028(行分隔符)或 U+2029(段落分隔符)。

断言 \b(词边界)匹配

1)单词的开头(当前字符是字母、数字或下划线,而前一个字符不是)。
2)单词的结尾(当前字符不是字母、数字或下划线,而前一个字符是其中之一)。
3)如果第一个字符是字母、数字或下划线,则匹配输入的开头(除非启用了 std::regex_constants::match_not_bow(C++ 仅))。
4)如果最后一个字符是字母、数字或下划线,则匹配输入的结尾(除非启用了 std::regex_constants::match_not_eow(C++ 仅))。

断言 \B(否定词边界)匹配除以下情况外的所有内容

1) 单词开头(当前字符是字母、数字或下划线,而前一个字符不是这些字符之一或不存在)
2) 单词结尾(当前字符不是字母、数字或下划线(或匹配器位于输入的末尾),而前一个字符是这些字符之一)

断言 ( ? = Disjunction )(零宽度正向先行断言)如果 Disjunction 在当前位置匹配输入,则匹配成功。

断言 ( ? ! Disjunction )(零宽度负向先行断言)如果 Disjunction 在当前位置不匹配输入,则匹配成功。

对于两种先行断言,在匹配 Disjunction 时,在匹配正则表达式的剩余部分之前,不会前进位置。此外,如果 Disjunction 可以以几种方式匹配当前位置,则只尝试第一种方式。

ECMAScript 禁止回溯到先行断言中的 Disjunction,这会影响从正则表达式的剩余部分到正向先行断言的回溯引用(见下面的示例)。从正则表达式的其余部分到负向先行断言的回溯引用始终未定义(因为先行断言中的 Disjunction 必须失败才能继续进行)。

注意:先行断言可用于在多个正则表达式之间创建逻辑 AND(见下面的示例)。

#include <cstddef>
#include <iostream>
#include <regex>
#include <string>
 
void show_matches(const std::string& in, const std::string& re)
{
    std::smatch m;
    std::regex_search(in, m, std::regex(re));
    if (!m.empty())
    {
        std::cout << "input=[" << in << "], regex=[" << re << "]\n  "
                     "prefix=[" << m.prefix() << "]\n  smatch: ";
        for (std::size_t n = 0; n < m.size(); ++n)
            std::cout << "m[" << n << "]=[" << m[n] << "] ";
        std::cout << "\n  suffix=[" << m.suffix() << "]\n";
    }
    else
        std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n";
}
 
int main()
{
    // matches the a at the end of input
    show_matches("aaa", "a$");
 
    // matches the o at the end of the first word
    show_matches("moo goo gai pan", "o\\b");
 
    // the lookahead matches the empty string immediately after the first b
    // this populates m[1] with "aaa" although m[0] is empty
    show_matches("baaabac", "(?=(a+))");
 
    // because backtracking into lookaheads is prohibited, 
    // this matches aba rather than aaaba
    show_matches("baaabac", "(?=(a+))a*b\\1");
 
    // logical AND via lookahead: this password matches IF it contains
    // at least one lowercase letter
    // AND at least one uppercase letter
    // AND at least one punctuation character
    // AND be at least 6 characters long
    show_matches("abcdef", "(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}");
    show_matches("aB,def", "(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}");
}

输出

input=[aaa], regex=[a$]
  prefix=[aa]
  smatch: m[0]=[a] 
  suffix=[]
input=[moo goo gai pan], regex=[o\b]
  prefix=[mo]
  smatch: m[0]=[o] 
  suffix=[ goo gai pan]
input=[baaabac], regex=[(?=(a+))]
  prefix=[b]
  smatch: m[0]=[] m[1]=[aaa] 
  suffix=[aaabac]
input=[baaabac], regex=[(?=(a+))a*b\1]
  prefix=[baa]
  smatch: m[0]=[aba] m[1]=[a] 
  suffix=[c]
input=[abcdef], regex=[(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}]: NO MATCH
input=[aB,def], regex=[(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}]
  prefix=[]
  smatch: m[0]=[aB,def] 
  suffix=[]

[edit] 原子

一个 原子 可以是以下之一

原子 :

模式字符
.
\ 原子转义
字符类
( Disjunction )
( ? : Disjunction )

其中 原子转义 :

十进制转义
字符转义
字符类转义

不同类型的原子具有不同的评估方式。

[edit] 子表达式

原子 ( Disjunction ) 是一个标记的子表达式:它执行 Disjunction 并将由 Disjunction 消费的输入子字符串的副本存储在子匹配数组中,该数组的索引对应于在整个正则表达式中遇到的标记子表达式的左括号 ( 的次数在这一点上。

除了在 std::match_results 中返回外,捕获的子匹配还可以作为回溯引用(\1\2 等)访问,并且可以在正则表达式中引用。请注意 std::regex_replace 使用 $ 而不是 \ 来表示回溯引用($1$2 等),与 String.prototype.replace(ECMA-262,第 15.5.4.11 部分)中的方式相同。

原子 ( ? : Disjunction )(非标记子表达式)只是评估 Disjunction 并且不会将其结果存储在子匹配中。这纯粹是词法分组。

[edit] 回溯引用

十进制转义 :

十进制整型字面量 [先行断言十进制数字]

如果 \ 后面跟着一个十进制数字 N,其第一个数字不是 0,则转义序列被认为是 回溯引用。通过在每个数字上调用 std::regex_traits::value(C++ 仅限) 并使用基数 10 算术组合其结果来获得值 N。如果 N 大于整个正则表达式中左捕获括号的总数,则会发生错误。

当回溯引用 \N 作为 原子 出现时,它匹配与子匹配数组中第 N 个元素当前存储的相同子字符串。

十进制转义 \0 不是回溯引用:它是一个字符转义,表示 NUL 字符。它不能后面跟着十进制数字。

如上所述,请注意 std::regex_replace 使用 $ 而不是 \ 来表示回溯引用($1$2 等)。

[edit] 单个字符匹配

原子 . 匹配并消耗输入字符串中的任何一个字符,除了 行终止符U+000DU+000AU+2029U+2028

原子 模式字符(其中 模式字符 是任何 源字符,除了字符 ^ $ \ . * + ? ( ) [ ] { } |,如果它等于此 模式字符,则匹配并消耗输入中的一个字符。

此以及所有其他单个字符匹配的相等性定义如下

1) 如果 std::regex_constants::icase 设置,如果 std::regex_traits::translate_nocase 的返回值相等,则字符相等 (C++ 仅限).
2) 否则,如果 std::regex_constants::collate 设置,如果 std::regex_traits::translate 的返回值相等,则字符相等 (C++ 仅限).
3) 否则,如果 operator== 返回 true,则字符相等。

每个由转义字符 \ 后跟 字符转义 以及特殊十进制转义 \0 组成的 原子,如果它等于由 字符转义 表示的字符,则匹配并消耗输入中的一个字符。识别以下字符转义序列

字符转义 :

控制转义
c 控制字母
十六进制转义序列
Unicode 转义序列
标识转义

这里,控制转义 是以下五个字符之一:f n r t v

控制转义 代码单元 名称
f U+000C 换页
n U+000A 换行
r U+000D 回车
t U+0009 水平制表符
v U+000B 垂直制表符

控制字母 是任何小写或大写 ASCII 字母,此字符转义匹配其代码单元值等于 控制字母 的代码单元值除以 32 的余数的字符。例如,\cD\cd 都匹配代码单元 U+0004(EOT),因为 'D' 是 U+0044 并且 0x44 % 32 == 4,而 'd' 是 U+0064 并且 0x64 % 32 == 4.

十六进制转义序列 是字母 x 后面紧跟正好两个 十六进制数字(其中 十六进制数字0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F 之一)。此字符转义匹配其代码单元值等于两位十六进制数字的数值的字符。

Unicode 转义序列 是字母 u 后面紧跟正好四个 十六进制数字。此字符转义匹配其代码单元值等于此四位十六进制数字的数值的字符。如果该值不适合此 std::basic_regexCharT,则会抛出 std::regex_error (C++ 仅限).

标识转义 可以是任何非字母数字字符:例如,另一个反斜杠。它按原样匹配该字符。

#include <cstddef>
#include <iostream>
#include <regex>
#include <string>
 
void show_matches(const std::wstring& in, const std::wstring& re)
{
    std::wsmatch m;
    std::regex_search(in, m, std::wregex(re));
    if (!m.empty())
    {
        std::wcout << L"input=[" << in << L"], regex=[" << re << L"]\n  "
                      L"prefix=[" << m.prefix() << L"]\n  wsmatch: ";
        for (std::size_t n = 0; n < m.size(); ++n)
            std::wcout << L"m[" << n << L"]=[" << m[n] << L"] ";
        std::wcout << L"\n  suffix=[" << m.suffix() << L"]\n";
    }
    else
        std::wcout << L"input=[" << in << "], regex=[" << re << L"]: NO MATCH\n";
}
 
int main()
{
    // Most escapes are similar to C++, save for metacharacters. You will have to
    // double-escape or use raw strings on the slashes though.
    show_matches(L"C++\\", LR"(C\+\+\\)");
 
    // Escape sequences and NUL.
    std::wstring s(L"ab\xff\0cd", 5);
    show_matches(s, L"(\\0|\\u00ff)");
 
    // No matching for non-BMP Unicode is defined, because ECMAScript uses UTF-16
    // atoms. Whether this emoji banana matches can be platform dependent:
    // These need to be wide-strings!
    show_matches(L"\U0001f34c", L"[\\u0000-\\ufffe]+");
}

可能的输出

input=[C++\], regex=[C\+\+\\]
  prefix=[]
  wsmatch: m[0]=[C++\]
  suffix=[]
input=[ab?c], regex=[(\0{{!}}\u00ff)]
  prefix=[ab]
  wsmatch: m[0]=[?] m[1]=[?]
  suffix=[c]
input=[?], regex=[[\u0000-\ufffe]+]: NO MATCH

[edit] 字符类

一个原子可以表示一个字符类,也就是说,如果它属于预定义的字符组之一,它将匹配并消耗一个字符。

字符类可以通过字符类转义引入

原子 :

\ 字符类转义

或直接

原子 :

字符类

字符类转义是某些常见字符类的简写,如下所示

字符类转义 类名表达式(C++ 仅限) 含义
d [[:digit:]] 数字
D [^[:digit:]] 非数字
s [[:space:]] 空白字符
S [^[:space:]] 非空白字符
w [_[:alnum:]] 字母数字字符和字符 _
W [^_[:alnum:]] 除字母数字或 _ 以外的字符
在 C++ 中,每个字符类转义的精确含义都是根据与区域设置相关的命名字符类定义的,而不是通过像 ECMAScript 中那样明确列出可接受的字符。

一个 字符类 是一个方括号括起来的 类范围 序列,可以选择以否定运算符 ^ 开头。如果它以 ^ 开头,则此 原子 匹配任何不在所有 类范围 的并集表示的字符集中包含的字符。否则,此 原子 匹配任何包含在所有 类范围 的并集表示的字符集中包含的字符。

字符类 :

[ [ 先行断言 ∉ {^}] 类范围 ]
[ ^ 类范围 ]

类范围 :

[空]
非空类范围

非空类范围 :

类原子
类原子 非空类范围无连字符
类原子 - 类原子 类范围

如果非空类范围具有 类原子 - 类原子 形式,则它匹配从以下定义的范围内匹配的任何字符:(C++ 仅限)

第一个 类原子 必须匹配单个排序元素 c1,而第二个 类原子 必须匹配单个排序元素 c2。要测试输入字符 c 是否与该范围匹配,请执行以下步骤

1) 如果 std::regex_constants::collate 未开启,则通过直接比较代码点来匹配该字符:如果 c1 <= c && c <= c2,则匹配该字符
1) 否则(如果 std::regex_constants::collate 已启用)
1) 如果 std::regex_constants::icase 已启用,则将所有三个字符(cc1c2)传递给 std::regex_traits::translate_nocase
2) 否则(如果 std::regex_constants::icase 未设置),所有三个字符(cc1c2)都会传递给 std::regex_traits::translate
2) 使用 std::regex_traits::transform 对得到的字符串进行比较,如果 transformed c1 <= transformed c && transformed c <= transformed c2,则匹配字符 c

如果字符 - 出现在以下位置,则会按照字面意思处理:

  • ClassRanges 的第一个或最后一个字符
  • 用连字符分隔的范围规范的开头或结尾 ClassAtom
  • 紧随用连字符分隔的范围规范。
  • 用反斜杠作为 CharacterEscape 进行转义

NonemptyClassRangesNoDash :

类原子
ClassAtomNoDash NonemptyClassRangesNoDash
ClassAtomNoDash - ClassAtom ClassRanges

ClassAtom :

-
ClassAtomNoDash
ClassAtomExClass(C++ 仅限)
ClassAtomCollatingElement(C++ 仅限)
ClassAtomEquivalence(C++ 仅限)

ClassAtomNoDash :

SourceCharacter,但不是 \ 或 ] 或 - 中的任何一个
\ ClassEscape

每个 ClassAtomNoDash 代表一个字符 - SourceCharacter 本身,或者通过以下方式转义

ClassEscape :

十进制转义
b
字符转义
字符类转义

特殊的 ClassEscape \b 生成一个匹配代码单元 U+0008(退格)的字符集。在 CharacterClass 之外,它是字边界 Assertion

CharacterClass 内使用 \B 和任何反向引用(DecimalEscape 除了零)都是错误。

在某些情况下,字符 -] 可能需要转义才能被视为原子。其他字符(如 *?)在 CharacterClass 之外具有特殊含义,不需要转义。

[编辑] 基于 POSIX 的字符类

这些字符类是对 ECMAScript 语法的扩展,等效于在 POSIX 正则表达式中找到的字符类。

ClassAtomExClass(C++ 仅限) :

[: ClassName :]

代表所有属于命名字符类 ClassName 的字符。该名称仅在 std::regex_traits::lookup_classname 对此名称返回非零值时才有效。如 std::regex_traits::lookup_classname 中所述,以下名称保证可以识别:alnum, alpha, blank, cntrl, digit, graph, lower, print, punct, space, upper, xdigit, d, s, w。其他名称可能会由系统提供的语言环境(例如日语中的 jdigitjkanji)提供,或作为用户定义的扩展来实现。

ClassAtomCollatingElement(C++ 仅限) :

[. ClassName .]

代表命名整理元素,该元素可能代表一个字符或一系列字符,在注入的语言环境下作为单个单元进行整理,例如捷克语中的 [.tilde.][.ch.]。该名称仅在 std::regex_traits::lookup_collatename 不是空字符串时才有效。

使用 std::regex_constants::collate 时,整理元素始终可以用作范围的端点(例如匈牙利语中的 [[.dz.]-g])。

ClassAtomEquivalence(C++ 仅限) :

[= ClassName =]

代表所有属于与命名整理元素相同等价类的字符,即所有其主整理键与整理元素 ClassName 的主整理键相同的字符。该名称仅在 std::regex_traits::lookup_collatename 对该名称返回非空字符串,并且 std::regex_traits::transform_primarystd::regex_traits::lookup_collatename 调用的结果返回的非空字符串时才有效。

主要排序键是忽略大小写、重音符号或特定于语言环境的定制的排序键;因此,例如 [[=a=]] 匹配以下任意字符:a, À, Á, Â, Ã, Ä, Å, A, à, á, â, ã, ä and å.

ClassName(C++ 仅限) :

ClassNameCharacter
ClassNameCharacter ClassName

ClassNameCharacter(C++ 仅限) :

SourceCharacter,但不是 . = : 中的任何一个