修改后的 ECMAScript 正则表达式语法
本页描述了当使用 ECMAScript
(默认值)作为 syntax_option_type
构建 std::basic_regex 时所使用的正则表达式语法。有关其他支持的正则表达式语法,请参阅 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 指南。
[编辑] 备选项
正则表达式模式是一个或多个 Alternative 的序列,它们由析取运算符 |
分隔(换句话说,析取运算符的优先级最低)。
模式 ::
- 析取
析取 ::
- 备选项
- 备选项
|
析取
模式首先尝试跳过 Disjunction 并匹配左侧的 Alternative,然后匹配正则表达式的其余部分(在 Disjunction 之后)。
如果失败,它会尝试跳过左侧的 Alternative 并匹配右侧的 Disjunction(后跟正则表达式的其余部分)。
如果左侧的 Alternative、右侧的 Disjunction 和正则表达式的其余部分都有选择点,那么在继续左侧 Alternative 中的下一个选择之前,会尝试表达式其余部分中的所有选择。如果左侧 Alternative 中的选择已用尽,则尝试右侧 Disjunction 而不是左侧 Alternative。
跳过的 Alternative 内的任何捕获括号都会产生空子匹配。
#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=[]
[编辑] 项
每个 Alternative 要么为空,要么是 Term 的序列(Term 之间没有分隔符)
备选项 ::
- [空]
- 备选项 项
空 Alternative 总是匹配,并且不消耗任何输入。
连续的 Term 尝试同时匹配输入中连续的部分。
如果左侧 Alternative、右侧 Term 和正则表达式的其余部分都有选择点,那么在继续右侧 Term 中的下一个选择之前,会尝试表达式其余部分中的所有选择,并且在继续左侧 Alternative 中的下一个选择之前,会尝试右侧 Term 中的所有选择。
#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]
[编辑] 量词
- 每个 Term 要么是一个 Assertion(见下文),要么是一个 Atom(见下文),要么是一个紧跟着 Quantifier 的 Atom
项 ::
- 断言
- 原子
- 原子 量词
每个 Quantifier 要么是 贪婪 量词(仅由一个 QuantifierPrefix 组成),要么是 非贪婪 量词(由一个 QuantifierPrefix 后面跟一个问号 ?
组成)。
量词 ::
- 量词前缀
- 量词前缀
?
每个 QuantifierPrefix 确定两个数字:最小重复次数和最大重复次数,如下所示
量词前缀 | 最小 | 最大 |
---|---|---|
*
|
零 | 无穷大 |
+
|
一 | 无穷大 |
?
|
零 | 一 |
{ 十进制数字 } |
十进制数字的值 | 十进制数字的值 |
{ 十进制数字 , } |
十进制数字的值 | 无穷大 |
{ 十进制数字 , 十进制数字 } |
逗号前的十进制数字的值 | 逗号后的十进制数字的值 |
单个 DecimalDigits 的值通过对每个数字调用 std::regex_traits::value(仅限 C++) 获得。
紧跟在 Quantifier 后面的 Atom 会按照 Quantifier 指定的次数重复。一个 Quantifier 可以是 非贪婪的,在这种情况下,Atom 模式会尽可能少地重复,同时仍然匹配正则表达式的其余部分;或者它可以是 贪婪的,在这种情况下,Atom 模式会尽可能多地重复,同时仍然匹配正则表达式的其余部分。
重复的是 Atom 模式,而不是它匹配的输入,因此 Atom 的不同重复可以匹配不同的输入子字符串。
如果 Atom 和正则表达式的其余部分都有选择点,则 Atom 首先尽可能多地(如果是非贪婪的,则尽可能少地)匹配。在移至 Atom 最后一次重复中的下一个选择之前,会尝试正则表达式其余部分中的所有选择。在移至 Atom 倒数第二次 (n-1) 次重复中的下一个选择之前,会尝试 Atom 最后一次 (n 次) 重复中的所有选择;此时可能会发现 Atom 的重复次数可以更多或更少;这些重复(再次,从尽可能少或尽可能多开始)在移至 Atom (n-1) 次重复中的下一个选择之前被用尽,依此类推。
每次 Atom 重复时,其捕获都会被清除(请参阅下面的 "(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
-
(
?
=
析取)
-
(
?
!
析取)
断言 ^
(行首)匹配
断言 $
(行尾)匹配
在上述两个断言和下面的 Atom .
中,LineTerminator 是以下四个字符之一:U+000A
(\n
或换行)、U+000D
(\r
或回车)、U+2028
(行分隔符)或 U+2029
(段落分隔符)
断言 \b
(单词边界)匹配
断言 \B
(非单词边界)匹配除了以下情况之外的所有内容
断言 (
?
=
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=[]
[编辑] 原子
一个 Atom 可以是以下之一
原子 ::
- 模式字符
-
.
-
\
原子转义 - 字符类
-
(
析取)
-
(
?
:
析取)
其中 AtomEscape:
- 十进制转义
- 字符转义
- 字符类转义
不同类型的原子求值方式不同。
[编辑] 子表达式
Atom (
Disjunction )
是一个标记的子表达式:它执行 Disjunction 并将 Disjunction 消耗的输入子字符串的副本存储在子匹配数组中,其索引对应于在整个正则表达式中此刻遇到的标记子表达式的左括号 (
的次数。
除了在 std::match_results 中返回之外,捕获的子匹配还可以作为反向引用(\1
、\2
等)进行访问,并在正则表达式中引用。请注意,std::regex_replace 使用 $
代替 \
来表示反向引用($1
、$2
等),其方式与 String.prototype.replace
(ECMA-262, 第 15.5.4.11 部分) 相同。
Atom (
?
:
Disjunction )
(非标记子表达式)只评估 Disjunction,而不将其结果存储在子匹配中。这纯粹是一个词法分组。
本节不完整 原因:无示例 |
[编辑] 反向引用
十进制转义 ::
- DecimalIntegerLiteral [lookahead ∉ DecimalDigit]
如果 \
后跟一个十进制数 N
,且其第一位不是 0
,则该转义序列被视为 反向引用。值 N
通过对每个数字调用 std::regex_traits::value(仅限 C++) 并使用十进制算术组合其结果获得。如果 N
大于整个正则表达式中左捕获括号的总数,则为错误。
当反向引用 \N
作为 Atom 出现时,它匹配与当前存储在子匹配数组的第 N 个元素中的子字符串相同的子字符串。
十进制转义 \0
不是反向引用:它是一个字符转义,表示 NUL 字符。它后面不能跟十进制数字。
如上所述,请注意 std::regex_replace 使用 $
代替 \
来表示反向引用($1
、$2
等)。
本节不完整 原因:无示例 |
[编辑] 单字符匹配
Atom .
匹配并消耗输入字符串中的任何一个字符,除了 LineTerminator(U+000D
、U+000A
、U+2029
或 U+2028
)
Atom PatternCharacter,其中 PatternCharacter 是除字符 ^ $ \ . * + ? ( ) [ ] { } |
之外的任何 SourceCharacter,如果它等于此 PatternCharacter,则匹配并消耗输入中的一个字符。
此和所有其他单字符匹配的相等性定义如下
每个由转义字符 \
后跟 CharacterEscape 组成的 Atom,以及特殊 DecimalEscape \0
,如果它等于 CharacterEscape 所表示的字符,则匹配并消耗输入中的一个字符。识别以下字符转义序列
字符转义 ::
- 控制转义
-
c
控制字母 - 十六进制转义序列
- Unicode转义序列
- 标识转义
在这里,ControlEscape 是以下五个字符之一:f n r t v
控制转义 | 代码单元 | 名称 |
---|---|---|
f
|
U+000C | 换页 |
n
|
U+000A | 换行 |
r
|
U+000D | 回车 |
t
|
U+0009 | 水平制表符 |
v
|
U+000B | 垂直制表符 |
ControlLetter 是任何小写或大写 ASCII 字母,此字符转义匹配其代码单元值等于 ControlLetter 代码单元值除以 32 的余数的字符。例如,\cD
和 \cd
都匹配代码单元 U+0004
(EOT),因为 'D' 是 U+0044
,0x44 % 32 == 4,'d' 是 U+0064
,0x64 % 32 == 4。
HexEscapeSequence 是字母 x
后跟正好两个 HexDigit(其中 HexDigit 是 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
之一)。此字符转义匹配其代码单元等于两位十六进制数的数字值的字符。
UnicodeEscapeSequence 是字母 u
后跟正好四个 HexDigit。此字符转义匹配其代码单元等于此四位十六进制数的数字值的字符。如果该值不适合 std::basic_regex 的 CharT
,则会抛出 std::regex_error (仅限 C++)。
IdentityEscape 可以是任何非字母数字字符:例如,另一个反斜杠。它按原样匹配该字符。
#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
[编辑] 字符类
原子可以表示一个字符类,也就是说,如果它属于预定义字符组之一,它将匹配并消耗一个字符。
字符类可以通过字符类转义符引入
原子 ::
-
\
字符类转义
或者直接
原子 ::
- 字符类
字符类转义是某些常见字符类的简写,如下所示
字符类转义 | 类名表达式(仅限 C++) | 含义 |
---|---|---|
d
|
[[:digit:]]
|
数字 |
D
|
[^[:digit:]]
|
非数字 |
s
|
[[:space:]]
|
空白字符 |
S
|
[^[:space:]]
|
非空白字符 |
w
|
[_[:alnum:]]
|
字母数字字符和字符 _ |
W
|
[^_[:alnum:]]
|
除字母数字或 _ 之外的字符 |
CharacterClass 是一个用方括号括起来的 ClassRanges 序列,可选地以否定运算符 ^
开头。如果以 ^
开头,则此 Atom 匹配任何不属于所有 ClassRanges 的并集所表示的字符集的字符。否则,此 Atom 匹配任何属于所有 ClassRanges 的并集所表示的字符集的字符。
字符类 ::
-
[
[
lookahead ∉ {^
}] ClassRanges]
-
[
^
ClassRanges]
ClassRanges:
- [空]
- NonemptyClassRanges
NonemptyClassRanges ::
- ClassAtom
- ClassAtom NonemptyClassRangesNoDash
- ClassAtom - ClassAtom ClassRanges
如果非空类范围的形式为 ClassAtom - ClassAtom
,它匹配由以下方式定义的范围内的任何字符:(仅限 C++)
第一个 ClassAtom 必须匹配单个排序元素 c1
,第二个 ClassAtom 必须匹配单个排序元素 c2
。为了测试输入字符 c
是否由该范围匹配,执行以下步骤
transformed c1 <= transformed c && transformed c <= transformed c2
,则匹配字符 c
字符 -
在以下情况下被视为字面量
- ClassRanges 的第一个或最后一个字符
- 用破折号分隔的范围规范的开头或结尾 ClassAtom
- 紧跟在一个以破折号分隔的范围规范之后。
- 用反斜杠作为 CharacterEscape 转义
NonemptyClassRangesNoDash:
- ClassAtom
- ClassAtomNoDash NonemptyClassRangesNoDash
- ClassAtomNoDash - ClassAtom ClassRanges
ClassAtom ::
-
-
- ClassAtomNoDash
- ClassAtomExClass(仅限 C++)
- ClassAtomCollatingElement(仅限 C++)
- ClassAtomEquivalence(仅限 C++)
ClassAtomNoDash:
- SourceCharacter 但不是
\ 或 ] 或 -
之一 -
\
类转义
每个 ClassAtomNoDash 表示一个单一字符——要么是原样的 SourceCharacter,要么按如下方式转义
ClassEscape:
- 十进制转义
-
b
- 字符转义
- 字符类转义
特殊 ClassEscape \b
产生一个字符集,它匹配代码单元 U+0008(退格符)。在 CharacterClass 之外,它是单词边界 Assertion。
在 CharacterClass 内使用 \B
和使用任何反向引用(非零的 DecimalEscape)都是错误。
在某些情况下,字符 -
和 ]
可能需要转义才能被视为原子。在 CharacterClass 之外具有特殊含义的其他字符,例如 *
或 ?
,则不需要转义。
本节不完整 原因:无示例 |
[编辑] 基于 POSIX 的字符类
这些字符类是对 ECMAScript 语法的扩展,并且等同于 POSIX 正则表达式中发现的字符类。
ClassAtomExClass(仅限 C++):
-
[:
类名:]
表示属于命名字符类 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
。系统提供的区域设置(如日语中的 jdigit
或 jkanji
)或用户自定义扩展可以提供其他名称。
ClassAtomCollatingElement(仅限 C++):
-
[.
类名.]
表示命名的排序元素,它可能代表一个单一字符或在给定区域设置下作为一个单元进行排序的字符序列,例如捷克语中的 [.tilde.]
或 [.ch.]
。仅当 std::regex_traits::lookup_collatename 返回非空字符串时,该名称才有效。
使用 std::regex_constants::collate 时,排序元素始终可以用作范围的终点(例如匈牙利语中的 [[.dz.]-g]
)。
ClassAtomEquivalence(仅限 C++):
-
[=
类名=]
表示与命名排序元素属于同一等价类的所有字符,即,所有主要排序键与排序元素 ClassName 相同的字符。仅当 std::regex_traits::lookup_collatename 对于该名称返回非空字符串,并且对 std::regex_traits::lookup_collatename 的调用结果的 std::regex_traits::transform_primary 返回值非空时,该名称才有效。
主排序键忽略大小写、重音或区域特定调整;因此例如 [[=a=]]
匹配以下任何字符:a, À, Á, Â, Ã, Ä, Å, A, à, á, â, ã, ä 和 å。
类名(仅限 C++):
- 类名字符
- 类名字符 类名
类名字符(仅限 C++):
- SourceCharacter 但不是
. = :
之一
本节不完整 原因:无示例 |