C++ 标准库支持多种正则表达式语法。 本主题介绍在使用正则表达式时可用的语法变体。
正则表达式语法
要使用的正则表达式语法是通过使用一个
std::regex_constants::syntax_option_type
枚举值来指定的。 这些正则表达式语法在
std::regex_constants
中进行定义:
ECMAScript:最接近 JavaScript 和 .NET 语言使用的语法。
basic:POSIX basic 正则表达式或 BRE。
extended:POSIX extended 正则表达式或 ERE。
awk:这是 extended 的,但它具有更多对非打印字符的转义。
grep:这是 basic 的,但它也允许换行符 (
\n
) 字符分隔分支结构。
egrep:这是 extended 的,但它也允许换行符字符分隔分支结构。
默认情况下,如果未指定语法,则假定为 ECMAScript。 只能指定一个语法。
还可以应用几个标志:
icase
:匹配时忽略大小写。
nosubs
:忽略标记的匹配项(即括号中的表达式);不存储任何替代项。
optimize
:加快匹配速度,代价是构造时间可能更长。
collate
:使用区分区域设置的排序规则序列(例如
[a-z]
形式的范围)。
零个或多个标志可以与语法组合,以指定正则表达式引擎行为。 如果仅指定标志,则假定语法为 ECMAScript。
元素可以是下列项之一:
一般字符
,可匹配目标序列中的相同字符。
通配符
'.'
,可匹配目标序列中除换行符以外的任何字符。
[expr]
形式的括号表达式,可匹配目标序列中已包含在表达式
expr
定义的集合内的字符或排序规则元素;或采用
[^expr]
形式,可匹配目标序列中未包含在表达式
expr
定义的集合内的字符或排序规则元素。
表达式
expr
可以包含下列项的任意组合:
单个字符。 将该字符添加到
expr
定义的集合。
ch1-ch2
形式的字符范围。 将闭范围
[ch1, ch2]
中的值所表示的字符添加到
expr
定义的集合。
[:name:]
形式的字符类。 将命名类中的字符添加到
expr
定义的集合。
[=elt=]
形式的等价类。 将等效于
elt
的排序规则元素添加到
expr
定义的集合。
[.elt.]
形式的排序规则符号。 将排序规则元素
elt
添加到
expr
定义的集合。
定位点
。 定位点
^
可匹配目标序列的开头。 定位点
$
可匹配目标序列的末尾。
basic 和 grep 中 (子表达式) 或 \(子表达式\) 形式的捕获组,可匹配目标序列中与分隔符之间的模式匹配的字符序列。
\k
形式的标识转义,可匹配目标序列中的字符
k
。
a
可匹配目标序列
"a"
,但不匹配目标序列
"B"
、
"b"
或
"c"
。
.
可匹配所有目标序列
"a"
、
"B"
、
"b"
和
"c"
。
[b-z]
可匹配目标序列
"b"
和
"c"
,但不匹配目标序列
"a"
或
"B"
。
[:lower:]
可匹配目标序列
"a"
、
"b"
和
"c"
,但不匹配目标序列
"B"
。
(a)
可匹配目标序列
"a"
并将捕获组 1 与子序列
"a"
相关联,但不匹配目标序列
"B"
、
"b"
或
"c"
。
在 ECMAScript、basic 和 grep 中,元素也可以是
\dd
形式的后向引用,其中,
dd
表示一个十进制值,此值可匹配目标序列中的某一字符序列,而该序列与第 N 个捕获组所匹配的字符序列相同。
例如,
(a)\1
可匹配目标序列
"aa"
,因为第一个(而且是唯一一个)捕获组可匹配初始序列
"a"
,然后
\1
可匹配最终序列
"a"
。
在 ECMAScript 中,元素也可以是下列项之一:
(?: 子表达式) 形式的非捕获组。 可匹配目标序列中与分隔符之间的模式相符的字符序列。
\f
、
\n
、
\r
、
\t
或
\v
形式的有限文件格式转义。 它们分别匹配目标序列中的换页符、换行符、回车符、水平制表符和垂直制表符。
(= 子表达式) 形式的肯定断言。 可匹配目标序列中与分隔符之间的模式匹配的字符序列,但不会更改目标序列中的匹配位置。
(= 子表达式) 形式的否定断言。 可匹配目标序列中不与分隔符之间的模式匹配的任何字符序列,并且不会更改目标序列中的匹配位置。
\xhh
形式的十六进制转义序列。 可匹配目标序列中由两个十六进制数字
hh
表示的字符。
\uhhhh
形式的 unicode 转义序列。 可匹配目标序列中由四个十六进制数字
hhhh
表示的字符。
\ck
形式的控件转义序列。 可匹配由字符
k
命名的控制字符。
\b
形式的字边界断言。 当在目标序列中的当前位置紧跟在
字边界
之后时,此断言即匹配。
\B
形式的否定字边界断言。 当在目标序列中的当前位置紧跟在字边界之后时,此断言即匹配。
\d
、
\D
、
\s
、
\S
、
\w
、
\W
形式的 dsw 字符转义。 为字符类提供一个短名称。
(?:a)
可匹配目标序列
"a"
,但
"(?:a)\1"
无效,因为不存在捕获组 1。
(=a)a
可匹配目标序列
"a"
。 肯定断言可匹配目标序列中的初始序列
"a"
,并且正则表达式中的最终
"a"
可匹配目标序列中的初始序列
"a"
。
(!a)a
不匹配目标序列
"a"
。
a\b.
可匹配目标序列
"a~"
,但不匹配目标序列
"ab"
。
a\B.
可匹配目标序列
"ab"
,但不匹配目标序列
"a~"
。
在 awk 中,元素也可以是下列项之一:
\\
、
\a
、
\b
、
\f
、
\n
、
\r
、
\t
或
\v
形式的文件格式转义。 它们分别匹配目标序列中的反斜杠、警报符、退格符、换页符、换行符、回车符、水平制表符和垂直制表符。
\ooo
形式的八进制转义序列。 可匹配目标序列中由一个、两个或三个八进制数字
ooo
的值表示的字符。
除
肯定断言
、
否定断言
或
定位点
之外的任何元素都可以后接一个重复计数。 最普遍的一种重复计数采用 {min,max} 形式,或者在 basic 和 grep 中采用 \{min,max\} 形式。 后跟这种重复计数形式的元素可至少匹配 min 次连续出现的与该元素匹配的序列,最多不超过 max 次。
例如,
a{2,3}
可匹配目标序列
"aa"
和目标序列
"aaa"
,但不匹配目标序列
"a"
或目标序列
"aaaa"
。
重复计数也可以采用以下形式之一:
在 basic 和 grep 中,为 {min} 或 \{min}。 等效于 {min,min}。
在 basic 和 grep 中,为 {min,} 或 \{min,\}。 等效于 {min,unbounded}。
*
等效于 {0,unbounded}。
a{2}
可匹配目标序列
"aa"
,但不匹配目标序列
"a"
或目标序列
"aaa"
。
a{2,}
可匹配目标序列
"aa"
、目标序列
"aaa"
,以此类推,但不匹配目标序列
"a"
。
a*
可匹配目标序列
""
、目标序列
"a"
、目标序列
"aa"
,以此类推。
对于除 basic 和 grep 外的所有语法,重复计数还可以采用以下形式之一:
?
等效于 {0,1}。
+
等效于 {1,unbounded}。
a?
可匹配目标序列
""
和目标序列
"a"
,但不匹配目标序列
"aa"
。
a+
可匹配目标序列
"a"
、目标序列
"aa"
,以此类推,但不匹配目标序列
""
。
在 ECMAScript 中,所有形式的重复计数都可以后跟字符
?
,用于指定非贪婪重复。
无论是否后跟
重复计数
,正则表达式都可以串联成较长的正则表达式。 由此产生的表达式可匹配由分别与各个元素相符的序列串联而成的目标序列。
例如,
a{2,3}b
可匹配目标序列
"aab"
和目标序列
"aaab"
,但不匹配目标序列
"ab"
或目标序列
"aaaab"
。
在除 basic 和 grep 外的所有正则表达式语法中,串联正则表达式可后跟字符
|
(竖线)以及另一个串联正则表达式。 通过这种方式,可以组合任意数量的串联正则表达式。 由此产生的表达式可匹配与一个或多个串联正则表达式相符的任意目标序列。
当多个串联正则表达式与目标序列匹配时,ECMAScript 会选择第一个与序列匹配的串联正则表达式作为匹配项,这称为“首次匹配”。 其他正则表达式语法则选择可实现最长匹配的语法。
例如,
ab|cd
可匹配目标序列
"ab"
和目标序列
"cd"
,但不匹配目标序列
"abd"
或目标序列
"acd"
。
在 grep 和 egrep 中,换行符 (
\n
) 可用来分隔分支结构。
在 basic 和 grep 中,子表达式是一种串联。 在其他正则表达式语法中,子表达式是一种分支结构。
下表汇总了各种正则表达式语法中可用的功能:
basic
extended
ECMAScript
egrep
定位点可匹配目标字符串中的位置,而不匹配字符。
^
可匹配目标字符串的开头,而
$
可匹配目标字符串的末尾。
向后引用是一个反斜杠,后跟十进制值 N。它与第 n 个捕获组
的内容匹配。 N 的值不得超过反斜杠之前的捕获组数量。 在 basic 和 grep 中,N 的值由反斜杠之后的十进制数字决定。 在 ECMAScript 中,N 的值由紧跟在反斜杠之后的所有十进制数字决定。 因此,在 basic 和 grep 中,N 的值绝不会超过 9(即使正则表达式具有九个以上捕获组)。 在 ECMAScript 中,N 的值是无限的。
((a+)(b+))(c+)\3
可匹配目标序列
"aabbbcbbb"
。 后向引用
\3
可匹配第三个捕获组中的文本,即
"(b+)"
。 它不匹配目标序列
"aabbbcbb"
。
(a)\2
无效。
(b(((((((((a))))))))))\10
在 basic 和 ECMAScript 中具有不同的含义。 在 basic 中,后向引用是
\1
。 后向引用可匹配第一个捕获组的内容(即分别以
(b
开头和最后一个
)
结尾且位于后向引用之前的捕获组),最后的
0
可匹配普通字符
0
。 在 ECMAScript 中,后向引用是
\10
。 它可匹配第十个捕获组,即最里面的捕获组。
括号表达式
括号表达式用于定义一个字符和
排序规则元素
集合。 当括号表达式以字符
^
开头时,如果集合中没有元素与目标序列中的当前字符匹配,即表示匹配成功。 其他情况下,如果集合的任意元素与目标序列中的当前字符匹配,即表示匹配成功。
字符集可以通过列出
单个字符
、
字符值域
、
字符类
、
等价类
和
排序规则符号
的任意组合来定义。
捕获组用于将其内容标记为正则表达式语法中的一个单元,并对与其内容相匹配的目标文本设置标签。 与每个捕获组相关联的标签是一个数字,此数字由用于标记捕获组的左括号计数来决定,一直计数到(包括)用于标记当前捕获组的左括号。 在此实现中,最大捕获组数量为 31。
ab+
可匹配目标序列
"abb"
,但不匹配目标序列
"abab"
。
(ab)+
不匹配目标序列
"abb"
,但可匹配目标序列
"abab"
。
((a+)(b+))(c+)
可匹配目标序列
"aabbbc"
并将捕获组 1 与子序列
"aabbb"
相关联,将捕获组 2 与子序列
"aa"
相关联,将捕获组 3 与
"bbb"
相关联,并将捕获组 4 与子序列
"c"
相关联。
括号表达式中的字符类用于将命名类中的所有字符都添加到括号表达式所定义的字符集。 若要创建字符类,请使用
[:
,后跟字符类的名称,然后再跟
:]
。
在内部,字符类名称通过调用
id = traits.lookup_classname
来识别。 如果
ch
返回 TRUE,则字符
traits.isctype(ch, id)
属于这样的类。 默认的
regex_traits
模板支持下表中的类名称。
括号表达式中的字符值域用于将值域内的所有字符都添加到括号表达式所定义的字符集。 若要创建字符范围,请将字符
'-'
放在范围内第一个和最后一个字符之间。 字符范围可以将大于或等于第一个字符的数值、小于或等于最后一个字符的数值的所有字符都放在集合内。 请注意,这一添加的字符集取决于平台特定的字符表示法。 如果字符
'-'
位于括号表达式的开头或末尾,或者是字符范围的第一个或最后一个字符,则它表示其本身。
[0-7]
表示字符集 {
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
}。 它可匹配目标序列
"0"
、
"1"
,以此类推,但不匹配
"a"
。
在采用 ASCII 字符编码的系统上,
[h-k]
表示字符集 {
h
,
i
,
j
,
k
}。 它可匹配目标序列
"h"
、
"i"
,以此类推,但不匹配
"\x8A"
或
"0"
。
在采用 EBCDIC 字符编码的系统上,
[h-k]
表示字符集 {
h
,
i
,
'\x8A'
,
'\x8B'
,
'\x8C'
,
'\x8D'
,
'\x8E'
,
'\x8F'
,
'\x90'
,
j
,
k
}(
h
编码为
0x88
,
k
编码为
0x92
)。 它可匹配目标序列
"h"
、
"i"
、
"\x8A"
,以此类推,但不匹配
"0"
。
[-0-24]
表示字符集 {
-
,
0
,
1
,
2
,
4
}。
[0-2-]
表示字符集 {
0
,
1
,
2
,
-
}。
在采用 ASCII 字符编码的系统上,
[+--]
表示字符集 {
+
,
-
}。
但是,当使用区分区域设置的值域时,值域内的字符由区域设置的排序规则来决定。 排在值域定义第一个字符之后、值域定义最后一个字符之前的字符位于集合中。 这两个端字符也位于集合中。
排序规则元素
排序规则元素是一个当做单个字符来处理的多字符序列。
排序规则符号
括号表达式中的排序规则符号用于将
排序规则元素
添加到括号表达式所定义的集合。 若要创建排序规则符号,请使用
[.
,后跟排序规则元素,然后再跟
.]
控件转义序列
控件转义序列包含一个反斜杠,后跟字母
'c'
,然后再跟
'a'
到
'z'
(或
'A'
到
'Z'
)之间的一个字母。 它可匹配由该字母命名的 ASCII 控制字符。 例如,
"\ci"
可匹配目标序列
"\x09"
,因为 Ctrl+I 的值为
0x09
。
dsw 字符转义
如下表所示,dsw 字符转义是字符类的短名称。
等效命名类
默认命名类
括号表达式中的等价类用于将与等价类定义中的排序规则元素等效的所有字符和
排序规则元素
全部添加到括号表达式所定义的集合。
若要创建等价类,请使用
[=
,后跟排序规则元素,然后再跟
=]
。 在内部,如果
elt1
,则两个排序规则元素
elt2
和
traits.transform_primary(elt1.begin(), elt1.end()) == traits.transform_primary(elt2.begin(), elt2.end())
等效。
文件格式转义由通常的 C 语言字符转义序列
\\
、
\a
、
\b
、
\f
、
\n
、
\r
、
\t
和
\v
组成。 它们具有普通的含义,即分别表示反斜杠、警报符、退格符、换页符、换行符、回车符、水平制表符和垂直制表符。 在 ECMAScript 中,不允许使用
\a
和
\b
。 (允许使用
\\
,但它是一种标识转义,而不是一种文件格式转义)。
十六进制转义序列
十六进制转义序列包含一个反斜杠,后跟字母
x
,然后再跟两个十六进制数字 (
0-9a-fA-F
)。 它可匹配目标序列中与这两个数字所指定的值相等的字符。
例如,当采用 ASCII 字符编码时,
"\x41"
可匹配目标序列
"a"
。
标识转义包含一个反斜杠,后跟单个字符。 它可匹配该字符。 当字符具有特殊含义时,需要用到它。 使用标识转义会移除特殊含义。 例如:
a*
可匹配目标序列
"aaa"
,但不匹配目标序列
"a*"
。
a\*
不匹配目标序列
"aaa"
,但可匹配目标序列
"a*"
。
如下表所示,标识转义中允许使用的字符集取决于正则表达式语法。
允许使用的标识转义字符
[abc]
可匹配目标序列
"a"
、
"b"
和
"c"
,但不匹配序列
"d"
。
[^abc]
可匹配目标序列
"d"
,但不匹配目标序列
"a"
、
"b"
或
"c"
。
[a^bc]
可匹配目标序列
"a"
、
"b"
、
"c"
和
"^"
,但不匹配目标序列
"d"
。
在除 ECMAScript 之外的任何正则表达式语法中,如果
]
紧跟在左括号
[
之后或紧跟第一个
^
之后,则该字符表示其本身。
[]a
无效,因为没有
]
来结束括号表达式。
[]abc]
可匹配目标序列
"a"
、
"b"
、
"c"
和
"]"
,但不匹配目标序列
"d"
。
[^]abc]
可匹配目标序列
"d"
,但不匹配目标序列
"a"
、
"b"
、
"c"
或
"]"
。
在 ECMAScript 中,请在括号表达式中使用
\]
来表示字符
]
。
[]a
可匹配目标序列
"a"
,因为括号表达式为空。
[\]abc]
可匹配目标序列
"a"
、
"b"
、
"c"
和
"]"
,但不匹配目标序列
"d"
。
否定断言可匹配除其内容外的任意项。 它不占用目标序列中的任何字符。
例如,
(!aa)(a*)
可匹配目标序列
"a"
并将捕获组 1 与子序列
"a"
相关联。 它不匹配目标序列
"aa"
或目标序列
"aaa"
。
否定字边界断言
如果目标字符串中的当前位置并非紧跟在字边界之后,则否定字边界断言匹配。
非捕获组用于将其内容标记为正则表达式语法中的一个单元,但不会对目标文本设置标签。
例如,
(a)(?:b)*(c)
可匹配目标文本
"abbc"
,并将捕获组 1 与子序列
"a"
相关联,将捕获组 2 与子序列
"c"
相关联。
非贪婪重复
非贪婪重复将占用与模式匹配的目标序列的最短子序列。 贪婪重复将占用最长子序列。 例如,
(a+)(a*b)
可匹配目标序列
"aaab"
。
当使用非贪婪重复时,它会将捕获组 1 与目标序列开头的子序列
"a"
相关联,将捕获组 2 与目标序列末尾的子序列
"aab"
相关联。
当使用贪婪匹配时,它会将捕获组 1 与子序列
"aaa"
相关联,将捕获组 2 与子序列
"b"
相关联。
八进制转义序列
八进制转义序列包含一个反斜杠,后跟一个、两个或三个八进制数字 (0-7)。 它可匹配目标序列中与这些数字所指定的值相等的字符。 如果数字全部为
0
,则序列无效。
例如,当采用 ASCII 字符编码时,
\101
可匹配目标序列
"a"
。
普通字符是在当前语法中没有特殊含义的任何有效字符。
在 ECMAScript 中,下列字符具有特殊含义:
^
$
\
.
*
+
?
(
)
[
]
{
}
|
在 basic 和 grep 中,下列字符具有特殊含义:
.
[
\
此外,在 basic 和 grep 中,当在特定上下文中使用下列字符时,它们具有特殊含义:
除下列情况外,
*
在所有情况下均具有特殊含义:它是正则表达式中的第一个字符或紧跟在正则表达式中第一个
^
之后,或者,它是捕获组的第一个字符或紧跟在捕获组中第一个
^
之后。
当
^
是正则表达式的第一个字符时,它具有特殊含义。
当
$
是正则表达式的最后一个字符时,它具有特殊含义。
在 extended、egrep 和 awk 中,下列字符具有特殊含义:
.
[
\
(
*
+
?
{
|
此外,在 extended、egrep 和 awk 中,当在特定上下文中使用下列字符时,它们具有特殊含义。
当
)
与前面的
(
匹配时,它具有特殊含义
当
^
是正则表达式的第一个字符时,它具有特殊含义。
当
$
是正则表达式的最后一个字符时,它具有特殊含义。
普通字符可匹配目标序列中的相同字符。 默认情况下,如果两个字符由相同的值表示,即表示匹配成功。 在不区分大小写的匹配中,如果
ch0
,则两个字符
ch1
和
traits.translate_nocase(ch0) == traits.translate_nocase(ch1)
匹配。 在区分区域设置的匹配中,如果
ch0
,则两个字符
ch1
和
traits.translate(ch0) == traits.translate(ch1)
匹配。
肯定断言可匹配其内容,但不占用目标序列中的任何字符。
(=aa)(a*)
可匹配目标序列
"aaaa"
并将捕获组 1 与子序列
"aaaa"
相关联。
(aa)(a*)
可匹配目标序列
"aaaa"
,并将捕获组 1 与目标序列开头的子序列
"aa"
相关联,将捕获组 2 与目标序列末尾的子序列
"aa"
相关联。
(=aa)(a)|(a)
可匹配目标序列
"a"
,并将捕获组 1 与空序列相关联(因为肯定断言失败),将捕获组 2 与子序列
"a"
相关联。 它还可匹配目标序列
"aa"
,并将捕获组 1 与子序列
"aa"
相关联,将捕获组 2 与空序列相关联。
Unicode 转义序列
unicode 转义序列包含一个反斜杠,后跟字母
'u'
,然后再跟四个十六进制数字 (
0-9a-fA-F
)。 它与具有由四个数字指定的值的目标序列中的字符匹配。 例如,当采用 ASCII 字符编码时,
\u0041
可匹配目标序列
"a"
。
通配符可匹配目标表达式中除换行符外的任何字符。
字边界在以下情况下出现:
当前字符位于目标序列的开头,并且是单词字符
A-Za-z0-9_
之一
当前字符位置超出目标序列的末尾,并且目标序列中的最后一个字符为一个单词字符。
当前字符是一个单词字符,而前面的字符不是。
当前字符不是一个单词字符,而前面的字符是。
字边界断言
当目标字符串中的当前位置紧跟在
字边界
之后时,字边界断言即匹配。
匹配和搜索
若要正则表达式与目标序列相匹配,整个正则表达式必须匹配整个目标序列。 例如,正则表达式
bcd
可匹配目标序列
"bcd"
,但不匹配目标序列
"abcd"
,也不匹配目标序列
"bcde"
。
若要成功执行正则表达式搜索,目标序列中的某个位置必须具有与正则表达式相匹配的子序列。 搜索通常会从左到右查找最匹配的子序列。
在目标序列
"bcd"
中搜索正则表达式
bcd
可以成功,并会匹配整个序列。 在目标序列
"abcd"
中进行相同的搜索也可以成功,并会匹配后三个字符。 在目标序列
"bcde"
中进行相同的搜索也可以成功,并会匹配前三个字符。
在目标序列
"bcdbcd"
中搜索正则表达式
bcd
可以成功,并会匹配前三个字符。
当在目标序列中的某些位置具有多个匹配的子序列时,可通过两种方式来选择匹配的模式。
第一匹配
将选择与正则表达式匹配时第一个找到的子序列。
最长匹配
将从在该位置匹配的子序列中选择最长的一个。 如果最长的子序列不止一个,则最长匹配方法将选择第一个找到的子序列。
例如,如果使用首次匹配方法,则在目标序列
"abcd"
中搜索正则表达式
b|bc
时会匹配子序列
"b"
,因为分支结构的左侧搜索词与该子序列匹配;因此,首次匹配方法不会尝试匹配分支结构的右侧搜索词。 当使用最长匹配方法时,进行同样的搜索会匹配
"bc"
,因为
"bc"
比
"b"
要长。
如果匹配到达目标序列的末尾而未失败,则部分匹配成功(即使尚未到达正则表达式的末尾)。 因此,在部分匹配成功后,目标序列的附加字符可能会导致之后的部分匹配失败。 但是,在部分匹配失败后,目标序列的附加字符不可能会导致之后的部分匹配成功。 例如,在部分匹配时,
ab
可匹配目标序列
"a"
,但不匹配
"ac"
。
ECMAScript 格式规则
sed 格式规则