使用.NET正则表达式

04-13Ctrl+D 收藏本站

关灯 直达底部

Using.NET Regular Expressions

.NET正则表达式功能强大,语法清晰,通过完整而易于使用的类接口来操作。虽然微软的正则表达式包做得很漂亮,文档却相反——它非常糟糕。文档不够全面,编写不够清晰,缺乏组织,有时甚至不能保证正确性。我花了很长的时间才整理清楚,所以希望这一章的内容能够让读者更清楚地理解.NET的正则表达式。

正则表达式快速入门

Regex Quickstart

即使不需要知道正则类模型(regex class model)的细节,也可以直接上手使用.NET的正则表达式包。理解细节能够让我们获得更多的信息,提高工作效率,但是下面这些简单的例子没有明确创建任何正则类,细节将在例子之后提到。

使用正则表达式库的程序必须在文件的开头写上下面这条语句,下面的例子假设此句已经存在:

Imports System.Text.RegularExpressions

下面的例子都能正常处理String变量TestStr。本章的所有例子中,选用的变量名都以斜体标注。

快速入门:在字符串中寻找匹配

这段程序检查一个正则表达式是否能匹配字符串:

这个例子使用了匹配模式:

快速入门:匹配,获得匹配文本

这个例子显示正则表达式实际匹配的文本。如果没有匹配,TheNum就是空字符串。

这个例子使用了一个匹配模式:

快速入门:匹配,获得捕获文本

这段程序以字符串的形式返回第1个捕获分组的匹配文本:

请注意,在C#中应使用Groups[1]取代Groups(1)。

下面的程序目的相同,只是使用了match选项:

仍然是相同的程序,只是使用命名捕获:

快速入门:查找和替换

这个例子把输入的字符串转换为 HTML“安全”的字符,把特殊的 HTML 转换为 HTML entity:

replacement字符串(第3个参数)的处理是很特殊的,第424页的补充内容做了讲解。例如,在 replacement 字符串中,‘$&’会被正则表达式真正匹配的文本所替代,下面的例子给大写的单词添加<B>…</B>:

这个例子把<B>…</B>(使用不区分大小写的匹配)替换为<I>…</I>:

包概览

Package Overview

通过丰富而便捷的类结构,可以使用.NET正则表达式几乎所有的功能。下面这个完整的控制台程序,提供了关于整个包的概览,它明确使用各种对象来进行简单的匹配。

通过命令行提示符来执行,把「d+w+」应用到同样的文本,结果是:

matched [1st] from char#12 for 3 chars.

导入正则表达式名字空间

你注意到程序头部的 Imports System.Text.RegularExpressions 了吗?任何用到.NET正则对象的VB程序都必须写上这一条语句,才能通过编译。

C#中对应的是:

using System.Text.RegularExpressions;//C#中应这么写

这个例子说明了基本的正则对象的用法,下面两行主要行为:

也可以合并为一行:

Dim M as Match=Regex.Match(SampleText,"d+w+")\'对字符串应用pattern

合并的写法更容易使用,程序员需要输入的代码更少,需要记录的对象也更少。不过,它的效率会稍微低一些(☞432)。在下面几页中,我们首先会看到原始的对象,然后学习“便捷”函数,例如静态函数Regex.Match,以及合适的使用时机。

为简便起见,在程序片段的例子中,我会省略下面这几行:

本书的第96、99、204、219和237页出现过VB的例子,回顾它们也许有所帮助。

核心对象概览

Core Object Overview

在深入细节之前,先来看看.NET的正则对象模型。对象模型是一套类结构,正则表达式的各种功能通过它们来提供。.NET的正则功能通过7个高度交互的类来提供,实际上你可能只需要理解其中3个——也就是下一页的图9-1所示的3个类——即可,它们展示了对‘May· 16,·1998’重复应用「s+(d+)」的过程。

Regex对象

第一步是创建Regex对象,例如:

Dim R as Regex=New Regex("s+(d+)")

在这里,我们用一个Regex对象表示「s+(d+)」,将其保存在变量R中。获得Regex对象之后,我们可以通过Match(text)方法将其应用到一段文本,返回与第一次匹配结果相关的信息:

Dim M as Match=R.Match("May 16,1998")

图9-1:.NET正则表达式相关对象模型

Match对象

Regex对象的Match(…)方法通过创建并返回Match对象来提供匹配信息。Match对象有多个属性,包括Success(一个表示匹配是否成功的Boolean值)和Value(如果匹配成功,则保存实际匹配文本的副本)。稍后我们会看到Match的所有属性的列表。

Match对象返回的细节中还包括捕获型括号所匹配的文本。前面Perl的例子使用$1保存第一组捕获型括号匹配的文本。.NET提供了两种办法:如果要取得纯文本,可以按照索引值访问Match对象的Groups属性,例如Groups(1).Value,它等价于Perl的$1(请注意,C#中使用的是Groups[1].Value)。另一个办法是使用Result方法,请参考第429页。

Group对象

前一段中的Groups(1)其实是对Group对象的引用,后面的.Value引用它的Value属性(也就是此分组对应的文本)。每一组捕获型括号都对应一个Group对象,另外还有一个“虚拟分组(virtual group)”,其编号为0,它保存全局匹配的信息。

因此,MatchObj.Value 和 MatchObj.Groups(0).Value 是等价的——都是全局匹配的文本的副本。第一种写法更加简洁方便,但我们必须知道存在编号为0的分组,因为MatchObj.Groups.Count(也就是Match关联的分组的数目)包含了它。如果「s+(d+)」能够匹配成功,MatchObj.Groups.Count的值就是2(标号为0的全局匹配和$1)。

Capture对象

Capture对象的使用并不频繁,请参考第437页的介绍。

匹配时会计算出所有结果

把正则表达式应用到字符串中,得到一个 Match对象,此时所有的结果(匹配的位置,每个捕获分组匹配的内容等)都会计算出来,封装到Match对象中。访问Match对象的属性和方法,包括它的Group对象(及其属性和方法)只是取回已经计算好的结果。