Chapter 26. Regular Expressions

正则表达式语言标识字符模式。.NET类型支持的正则表达式基于Perl5正则表达式,同时支持查找与查找/替换功能。

正则表达式可以用于类似如下的任务:

  • 验证如密码与电话号码这样的文本输入(ASP.NET为此目的提供了RegularExpressionValidator控件)
  • 将文本数据分析为更为结构化的格式(例如由存储在数据库中HTML页面获取数据)
  • 替换文档中的文本格式(例如只替换整词)

本章分为介绍.NET正则表达式基础的概念部分以及描述正则表达式语言的参考部分。

所有的正则表达式类型定义于System.Text.RegularExpression名空空间中。

正则表达式基础

最常见的正则表达式之一是量词。?是一个匹配0个或是1个的量词。换句话说,?意味着可选的。一个正则或者是单个字符或者是位于方括号中的复杂字符结构。例如,正则表达式”colou?r”可以匹配color与colour,但是并不匹配colouur:

Console.WriteLine (Regex.Match ("color",   @"colou?r").Success);  // True
Console.WriteLine (Regex.Match ("colour",  @"colou?r").Success);  // True
Console.WriteLine (Regex.Match ("colouur", @"colou?r").Success);  // False

Regex.Math是一个较大的字符串内查找。其所返回的对象包含匹配的Index与Length属性以及实际匹配的Value:

Match m = Regex.Match ("any colour you like", @"colou?r");
Console.WriteLine (m.Success);     // True
Console.WriteLine (m.Index);       // 4
Console.WriteLine (m.Length);      // 6
Console.WriteLine (m.Value);       // colour
Console.WriteLine (m.ToString());  // colour

我们可以将Regex.Match方法看作string的IndexOf方法的更强大版本。所不同的是正则表达式搜索模式而不是字符串字面量。

IsMatch方法是调用Match然调用测试Success属性的简写。

默认情况下正则表达式引擎由左到右计算,所以只会返回最左端的匹配。我们可以使用NextMatch方法来返回更多的匹配:

Match m1 = Regex.Match ("One color? There are two colours in my head!",
                        @"colou?rs?");
Match m2 = m1.NextMatch();
Console.WriteLine (m1);         // color
Console.WriteLine (m2);         // colours

Matches方法会以数组形式返回所有的匹配。我们可以重写前面的示例:

foreach (Match m in Regex.Matches
          ("One color? There are two colours in my head!", @"colou?rs?"))
  Console.WriteLine (m);

另一个常用的正则表式操作符以竖线表示的或操作符。下面的正则表达式会匹配“Jen”,“Jenny”与“Jennifer”:

Console.WriteLine (Regex.IsMatch (“Jenny”, “Jen(ny|nifer)?”)); // True

或操作符两端的括号将其与表达式的其余部分离开。

编译的正则表达式

在前面的某些示例中,我们使用相同的模式重复调用静态的RegEx方法。另一种相对的方法则是使用模式实例化一个RegEx对象,然后调用实例方法:

Regex r = new Regex (@"sausages?");
Console.WriteLine (r.Match ("sausage"));   // sausage
Console.WriteLine (r.Match ("sausages"));  // sausages

这并不仅仅是语法约定:在其表象之下,RegEx实例使用轻量级的代码生成来动态构建与编译适应特定正则表达式的代码。结果则是以较小的初始编译代价获得更快速的匹配。

RegEx实例是不可修改的。

RegexOptions

RegexOptions标志枚举让我们可以调整匹配行为。RegexOptions的一个通常应用是执行大小写不敏感的查找:

Console.WriteLine (Regex.Match ("a", "A", RegexOptions.IgnoreCase)); //
a

大多数的RegexOptions标记也可以在表达式本身内使用一个符号代码来激活:

Console.WriteLine (Regex.Match ("a", @"(?i)A")); // a

我们可以使用表达式来打开或是关闭正则选项:

Console.WriteLine (Regex.Match ("AAAa", @"(?i)a(?-i)a")); // Aa

另一个有用的选项是IgnorePatternWhitespace或(?x)。这可以允许我们插入空格从而使得正则表达式更易读。

表格26-1列出了所有的RegExOoptions及其所对应在的单个字符:

Table: Table 26-1. Regular expression options

字符转义

正则表达式包含有下列的元字符,这些字符具有特殊的含义,而不是字面含义:

::
\ * + ? | { [ () ^ $ . #

要引用元字符的字面值,我们必须在这些字符前使用反斜线作为前缀。在下面的示例中,我们转义?字符来匹配“what?”:

Console.WriteLine (Regex.Match ("what?", @"what\?")); // what? (correct)
Console.WriteLine (Regex.Match ("what?", @"what?"));  // what  (incorrect)

Regex的Escape与Unescape方法通过将正则表达式元字符替换为对应的转义字符或是相反的操作来进行相应的字符串转换。例如:

Console.WriteLine (Regex.Escape (@"?")); // \?
Console.WriteLine (Regex.Unescape (@"\?")); // ?>

我们使用C#的@字面量来表示本章中的所有正则表达式字符串。这是通过传递C#的转义机制来实现的,当然这也可以使用反斜线来实现。如果没有@,反斜线字面量就需要四个反斜线:

Console.WriteLine (Regex.Match ("\\", "\\\\")); // \

除非我们包含(?x)选项,在正则表达式中空格被作为字面量进行处理:

Console.Write (Regex.IsMatch ("hello world", @"hello world")); // True

字符集

字符集扮演着特定字符集的通配符的角色。