正则表达式提供了功能强大、灵活而又高效的方法来处理文本。正则表达式的全面模式匹配表示法使您可以快速分析大量文本以找到特定的字符模式;提取、编辑、替换或删除文本子字符串;或将提取的字符串添加到集合以生成报告。对于处理字符串(例如 HTML 处理、日志文件分析和 HTTP 标头分析)的许多应用程序而言,正则表达式是不可缺少的工具。
Microsoft .NET Framework 正则表达式并入了其他正则表达式实现的最常见功能,例如在 Perl 和 awk 中提供的那些功能。被设计为与 Perl 5 正则表达式兼容,.NET Framework 正则表达式还包括一些在其他实现中尚未提供的功能,例如从右到左匹配和即时编译。
.NET Framework 正则表达式类是基类库的一部分,并且可以和面向公共语言运行库的任何语言或工具(包括 ASP.NET 和 Visual Studio 2005)一起使用。
1 正则表达式语言
为操纵文本,对正则表达式语言进行了精心设计和优化。正则表达式语言由两种基本字符类型组成:原义(正常)文本字符和元字符。元字符使正则表达式具有处理能力。
您可能比较熟悉在 DOS 文件系统中使用的 ? 和 * 元字符,这两个元字符分别代表任意单个字符和字符组。DOS 文件命令 COPY *.DOC A: 命令文件系统将文件扩展名为 .DOC 的所有文件均复制到 A 驱动器的磁盘中。元字符 * 代表文件扩展名 .DOC 前的任何文件名。正则表达式极大地拓展了此基本思路,提供大量的元字符组,使通过相对少的字符描述非常复杂的文本匹配表达式成为可能。
例如,正则表达式 /s2000 在应用到文本正文时,将匹配在字符串 “ 2000 ” 前为任意空白字符(例如空格或制表符)的所有匹配项。
注意
如果使用的是 C++、C# 或 JScript,则在特殊转义符(例如 /s)之前必须另加一个反斜杠(例如 “ //s2000" ” ),以表明转义符中的反斜杠是原义字符。否则,正则表达式引擎会将 /s 中的反斜杠和 s 当作两个单独的运算符来处理。如果使用的是 Visual Basic 2005,则不必添加反斜杠。如果使用的是 C#,则可以使用以 @ 为前缀并禁用转义的 C# 字符串(例如 @"/s2000")。
正则表达式还可以执行更为复杂的搜索。例如,正则表达式 (?<char>/w)/k<char> 使用命名分组和反向引用来搜索相邻的成对字符。当应用于 “ I'll have a small coffee ” 这一字符串时,它将在单词 “ I'll ” 、 “ small ” 和 “ coffee ” 中找到匹配项。
2 正则表达式语言元素
(1)字符转义
大多数重要的正则表达式语言运算符都是非转义的单个字符。转义符 /(单个反斜杠)通知正则表达式分析器反斜杠后面的字符不是运算符。例如,分析器将星号 (*) 视为重复限定符,而将后跟星号的反斜杠 (/*) 视为 Unicode 字符 002A。
下表中列出的字符转义在正则表达式和替换模式中都会被识别。
转义符 说明
一般字符 除 .$ ^ { [ ( | ) * + ? / 外,其他字符与自身匹配。
/a 与响铃(警报)/u0007 匹配。
/b 如果在 [] 字符类中,则与退格符 /u0008 匹配;如果不是这种情况, 请参见本表后面的 “ 注意 ” 部分。
/t 与 Tab 符 /u0009 匹配。
/r 与回车符 /u000D 匹配。
/v 与垂直 Tab 符 /u000B 匹配。
/f 与换页符 /u000C 匹配。
/n 与换行符 /u000A 匹配。
/e 与 Esc 符 /u001B 匹配。
/040 将 ASCII 字符匹配为八进制数(最多三位);如果没有前导零的数字只有一位数或者与捕获组号相对应,则该数字为后向引用。(有关更多信息,请参见反向引用。)例如,字符 /040 表示空格。
/x20 使用十六进制表示形式(恰好两位)与 ASCII 字符匹配。
/cC 与 ASCII 控制字符匹配;例如,/cC 为 Ctrl-C。
/u0020 使用十六进制表示形式(恰好四位)与 Unicode 字符匹配。
注意 :
.NET Framework 不支持用于指定 Unicode 的 Perl 5 字符转义。Perl 5 字符转义的格式是 /x{####…},其中 “ ####… ” 是十六进制数字的序列。应改为使用本行中描述的 .NET Framework 字符转义。
/ 在后面带有不识别为转义符的字符时,与该字符匹配。例如,/* 与 /x2A 相同。
注意 :
转义字符 /b 是一个特例。在正则表达式中,/b 表示单词边界(在 /w 和 /W 之间),不过,在 [] 字符类中,/b 表示退格符。在替换模式中,/b 始终表示退格符。
(2)替换
只在替换模式中允许替换。对于正则表达式中的类似功能,使用后向引用(如 /1)。有关后向引用的详细信息,请参见反向引用和后向引用构造。
字符转义和替换是在替换模式中识别的唯一的特殊构造。下面几部分描述的所有语法构造只允许出现在正则表达式中;替换模式中不识别它们。例如,替换模式 a*${txt}b 会插入字符串 “ a* ” ,该字符串后跟按 txt 捕获组匹配的子字符串,该子字符串后跟字符串 “ b ” (如果有)。在替换模式中,* 字符不会识别为元字符。与此类似,在正则表达式匹配模式中不识别 $ 模式。在正则表达式中,$ 指定字符串的结尾。
下表显示如何定义命名并编号的替换模式。
字符 说明
$ 数字 替换按组号 number(十进制)匹配的最后一个子字符串。
${ name } 替换由 (?<name> ) 组匹配的最后一个子字符串。
$$ 替换单个 “ $ ” 字符。
$& 替换完全匹配本身的一个副本。
$` 替换匹配前的输入字符串的所有文本。
$' 替换匹配后的输入字符串的所有文本。
$+ 替换最后捕获的组。
$_ 替换整个输入字符串。
(3)字符类
字符类是一个字符集,如果字符集中的任何一个字符有匹配,它就会找到该匹配项。下表总结了字符匹配语法。
字符类 说明
. 匹配除 /n 以外的任何字符。如果已用 Singleline 选项做过修改,则句点字符可与任何字符匹配。
[ aeiou ] 与指定字符集中包含的任何单个字符匹配。
[^ aeiou ] 与不在指定字符集中的任何单个字符匹配。
[0-9a-fA-F] 使用连字号 ( – ) 允许指定连续字符范围。
/p{ name } 与 {name} 指定的命名字符类中的任何字符都匹配。支持的名称为 Unicode 组和块范围。例如,Ll、Nd、Z、IsGreek、IsBoxDrawing。
/P{ name } 与在 {name} 中指定的组和块范围不包括的文本匹配。
/w 与任何单词字符匹配。等效于 Unicode 字符类别 [/p{Ll}/p{Lu}/p{Lt}/p{Lo}/p{Nd}/p{Pc}/p{Lm}]。如果用 ECMAScript 选项指定了符合 ECMAScript 的行为,则 /w 等效于 [a-zA-Z_0-9]。
/W 与任何非单词字符匹配。等效于 Unicode 字符类别 [^/p{Ll}/p{Lu}/p{Lt}/p{Lo}/p{Nd}/p{Pc}/p{Lm}]。如果用 ECMAScript 选项指定了符合 ECMAScript 的行为,则 /W 等效于 [^a-zA-Z_0-9]。
/s 与任何空白字符匹配。等效于 Unicode 字符类别 [/f/n/r/t/v/x85/p{Z}]。如果用 ECMAScript 选项指定了符合 ECMAScript 的行为,则 /s 等效于 [ /f/n/r/t/v]。
/S 与任何非空白字符匹配。等效于 Unicode 字符类别 [^/f/n/r/t/v/x85/p{Z}]。如果用 ECMAScript 选项指定了符合 ECMAScript 的行为,则 /S 等效于 [^ /f/n/r/t/v]。
/d 与任何十进制数字匹配。对于 Unicode 类别的 ECMAScript 行为,等效于 /p{Nd},对于非 Unicode 类别的 ECMAScript 行为,等效于 [0-9]。
/D 与任何非数字匹配。对于 Unicode 类别的 ECMAScript 行为,等效于 /P{Nd},对于非 Unicode 类别的 ECMAScript 行为,等效于 [^0-9]。
(4)正则表达式选项
可以使用影响匹配行为的选项修改正则表达式模式。可以通过下列两种基本方法之一设置正则表达式选项:可以在 Regex (pattern, options) 构造函数中的 options 参数中指定,其中 options 是 RegexOptions 枚举值的按位 “ 或 ” 组合;也可以使用内联 (?imnsx-imnsx:) 分组构造或 (?imnsx-imnsx) 其他构造在正则表达式模式内设置它们。
在内联选项构造中,一个选项或一组选项前面的减号 (-) 用于关闭这些选项。例如,内联构造 (?ix-ms) 将打开 IgnoreCase 和 IgnorePatternWhiteSpace 选项而关闭 Multiline 和 Singleline 选项。默认情况下,关闭所有正则表达式选项。
下表列出了 RegexOptions 枚举的成员以及等效的内联选项字符。请注意,选项 RightToLeft 和 Compiled 只适用于表达式整体而不允许内联。(它们只能在 Regex 构造函数的 options 参数中指定。)选项 None 和 ECMAScript 不允许内联。
RegexOption 成员 内联字符 说明
None N/A 指定不设置任何选项。
IgnoreCase i 指定不区分大小写的匹配。
Multiline m 指定多行模式。更改 ^ 和 $ 的含义,以使它们分别与任何行的开头和结尾匹配,而不只是与整个字符串的开头和结尾匹配。
ExplicitCapture n 指定唯一有效的捕获是显式命名或编号的 (?<name>…) 形式的组。这允许圆括号充当非捕获组,从而避免了由 (?:…) 导致的语法上的笨拙。
Compiled N/A 指定正则表达式将被编译为程序集。生成该正则表达式的 Microsoft 中间语言 (MSIL) 代码;以较长的启动时间为代价,得到更快的执行速度。
Singleline s 指定单行模式。更改句点字符 (.) 的含义,以使它与每个字符(而不是除 /n 之外的所有字符)匹配。
IgnorePatternWhitespace x 指定从模式中排除非转义空白并启用数字符号 (#) 后面的注释。(有关转义空白字符的列表,请参见字符转义。)请注意,空白永远不会从字符类中消除。
RightToLeft N/A 指定搜索是从右向左而不是从左向右进行的。具有此选项的正则表达式将移动到起始位置的左边而不是右边。(因此,起始位置应指定为字符串的结尾而不是开头。)为了避免构造具有无限循环的正则表达式的可能性,此选项不能在中流指定。但是,(?<) 回顾后发构造提供了可用作子表达式的类似替代物。 RightToLeft 只更改搜索方向。它不会反转所搜索的子字符串。预测先行和回顾后发断言不改变:预测先行向右搜索;回顾后发向左搜索。
ECMAScript N/A 指定已为表达式启用了符合 ECMAScript 的行为。此选项仅可与 IgnoreCase 和 Multiline 标志一起使用。将 ECMAScript 同任何其他标志一起使用将导致异常。
CultureInvariant N/A 指定忽略语言中的区域性差异。有关更多信息,请参见在 RegularExpressions 命名空间中执行不区分区域性的操作。
(5) 原子零宽度断言
下表中描述的元字符不会使引擎在字符串中前进或使用字符。它们只是根据字符串中的当前位置使匹配成功或失败。例如,^ 指定当前位置在行或字符串的开头。因此,正则表达式 ^FTP 只会返回那些在行的开头出现的字符串 “ FTP ” 的匹配项。
断言 说明
^ 指定匹配必须出现在字符串的开头或行的开头。有关更多信息,请参见正则表达式选项中的 Multiline 选项。
$ 指定匹配必须出现在以下位置:字符串结尾、字符串结尾处的 /n 之前或行的结尾。有关更多信息,请参见正则表达式选项中的 Multiline 选项。
/A 指定匹配必须出现在字符串的开头(忽略 Multiline 选项)。
/Z 指定匹配必须出现在字符串的结尾或字符串结尾处的 /n 之前(忽略 Multiline 选项)。
/z 指定匹配必须出现在字符串的结尾(忽略 Multiline 选项)。
/G 指定匹配必须出现在上一个匹配结束的地方。与 Match.NextMatch() 一起使用时,此断言确保所有匹配都是连续的。
/b 指定匹配必须出现在 /w(字母数字)和 /W(非字母数字)字符之间的边界上。匹配必须出现在单词边界上,即出现在由任何非字母数字字符分隔的单词中第一个或最后一个字符上。
/B 指定匹配不得出现在 /b 边界上。
(6)限定符
限定符将可选数量的数据添加到正则表达式。限定符表达式应用于紧挨着它前面的字符、组或字符类。.NET Framework 正则表达式支持最小匹配 (lazy) 限定符。
下表描述了影响匹配的元字符。数量 n 和 m 是整数常数。
限定符 说明
* 指定零个或更多个匹配;例如 /w* 或 (abc)*。等效于 {0,}。
+ 指定一个或多个匹配;例如 /w+ 或 (abc)+。等效于 {1,}。
? 指定零个或一个匹配;例如 /w? 或 (abc)?。等效于 {0,1}。
{ n } 指定恰好 n 个匹配;例如 (pizza){2}。
{ n ,} 指定至少 n 个匹配;例如 (abc){2,}。
{ n , m } 指定至少 n 个但不多于 m 个匹配。
*? 指定尽可能少地使用重复的第一个匹配(等效于 lazy *)。
+? 指定尽可能少地使用重复但至少使用一次(等效于 lazy +)。
?? 指定使用零次重复(如有可能)或一次重复 (lazy ?)。
{ n }? 等效于 {n} (lazy {n})。
{ n ,}? 指定尽可能少地使用重复但至少使用 n 次 (lazy {n,})。
{ n , m }? 指定介于 n 次和 m 次之间、尽可能少地使用重复 (lazy {n,m})。
(6)分组构造
分组构造使您可以捕获子表达式组并提高具有非捕获预测先行和回顾后发修饰符的正则表达式的效率。下表描述了正则表达式分组构造。
分组构造 说明
( ) 捕获匹配的子字符串(或非捕获组;有关更多信息,请参见正则表达式选项中的 ExplicitCapture 选项)。使用 () 的捕获根据左括号的顺序从 1 开始自动编号。捕获元素编号为零的第一个捕获是由整个正则表达式模式匹配的文本。
(?<name> ) 将匹配的子字符串捕获到一个组名称或编号名称中。用于 name 的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号,例如 (?'name')。
(?<name1-name2> ) 平衡组定义。删除先前定义的 name2 组的定义并在 name1 组中存储先前定义的 name2 组和当前组之间的间隔。如果未定义 name2 组,则匹配将回溯。由于删除 name2 的最后一个定义会显示 name2 的先前定义,因此该构造允许将 name2 组的捕获堆栈用作计数器以跟踪嵌套构造(如括号)。在此构造中,name1 是可选的。可以使用单引号替代尖括号,例如 (?'name1-name2')。
(?: ) 非捕获组。
(? imnsx-imnsx : ) 应用或禁用子表达式中指定的选项。例如,(?i-s: ) 将打开不区分大小写并禁用单行模式。有关更多信息,请参见正则表达式选项。
(?= ) 零宽度正预测先行断言。仅当子表达式在此位置的右侧匹配时才继续匹配。例如,/w+(?=/d) 与后跟数字的单词匹配,而不与该数字匹配。此构造不会回溯。
(?! ) 零宽度负预测先行断言。仅当子表达式不在此位置的右侧匹配时才继续匹配。例如,/b(?!un)/w+/b 与不以 un 开头的单词匹配。
(?<= ) 零宽度正回顾后发断言。仅当子表达式在此位置的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 后面的 99 的实例匹配。此构造不会回溯。
(?<! ) 零宽度负回顾后发断言。仅当子表达式不在此位置的左侧匹配时才继续匹配。
(?> ) 非回溯子表达式(也称为 “ 贪婪 ” 子表达式)。该子表达式仅完全匹配一次,然后就不会逐段参与回溯了。(也就是说,该子表达式仅与可由该子表达式单独匹配的字符串匹配。)
命名捕获根据左括号的从左到右的顺序按顺序编号(与非命名捕获类似),但在对所有非命名捕获进行计数之后才开始对命名捕获进行编号。例如,模式 ((?<One>abc)/d+)?(?<Two>xyz)(.*) 按编号和名称产生下列捕获组。(编号为 0 的第一个捕获总是指整个模式)。
编号 名称 模式
0 0(默认名称) ((?<One>abc)/d+)?(?<Two>xyz)(.*)
1 1(默认名称) ((?<One>abc)/d+)
2 2(默认名称) (.*)
3 1 (?<One>abc)
4 2 (?<Two>xyz)
(7)后向引用构造
下表列出了用于将后向引用修饰符添加到正则表达式中的可选参数。
后向引用构造 定义
/ 数字 后向引用。例如,(/w)/1 查找双写的单词字符。
/k<name> 命名后向引用。例如,(?<char>/w)/k<char> 查找双写的单词字符。表达式 (?<43>/w)/43 执行同样的操作。可以使用单引号替代尖括号,例如 /k'char'。
请注意八进制转义代码和使用相同表示法的 /number 后向引用之间的多义性。
(8)替换构造
下表列出了用于修改正则表达式以允许进行二者之一/或匹配的特殊字符。
替换构造 定义
| 与以 |(竖线)字符分隔的术语中的任何一项匹配;例如, cat|dog|tiger。使用最左侧的成功匹配。
(?( 表达式 )yes|no) 如果表达式在此位置匹配,则与 “ yes ” 部分匹配;否则,与 “ no ” 部分匹配。 “ no ” 部分可省略。表达式可以是任何有效的子表达式,但它将变为零宽度断言,因此该语法等效于 (?(?=expression)yes|no)。请注意,如果表达式是命名组的名称或捕获组编号,则替换构造将解释为捕获测试(在本表的下一行对此进行了描述)。若要避免在这些情况下产生混淆,则可以显式拼出内部 (?=expression)。
(?( name )yes|no) 如果命名捕获字符串有匹配,则与 “ yes ” 部分匹配;否则,与 “ no ” 部分匹配。 “ no ” 部分可省略。如果给定的名称不与此表达式中使用的捕获组的名称或编号对应,则替换构造将解释为表达式测试(在本表的上一行进行了描述)。
(9)其他构造
下表列出了用于修改正则表达式的子表达式。
构造 定义
(? imnsx - imnsx ) 对诸如不区分大小写这样的选项进行设置或禁用以使其在模式中间打开或关闭。有关特定选项的信息,请参见正则表达式选项。在封闭组结束之前,选项更改将一直有效。请参见有关分组构造(?imnsx-imnsx: ) 的信息,它是一个更为巧妙的形式。
(?# ) 插入到正则表达式内部的内联注释。该注释在第一个右括号字符处终止。
# [至行尾] X 模式注释。该注释以非转义的 # 开头,并继续到行的结尾。(请注意,必须激活 x 选项或 RegexOptions.IgnorePatternWhitespace 枚举选项才能识别此类注释。)