Regex 类包含各种静态方法,允许在不显式实例化其他类的对象的情况下使用其他正则表达式类.以下代码示例创建了 Regex 类的实例并在初始化对象时定义一个简单的正则表达式.请注意,使用了附加的反斜杠作为转义字符,它将 s 匹配字符类中的反斜杠指定为原义字符.
Regex r; // 声明一个 Regex类的变量r = new Regex( "\s2000" ); // 定义表达式
2.2 Match 类表示正则表达式匹配操作的结果
以下示例使用 Regex 类的 Match 方法返回 Match 类型的对象,以便找到输入字符串中第一个匹配.此示例使用 Match 类的 Match.Success 属性来指示是否已找到匹配.
Regex r = new Regex( "abc" ); // 定义一个Regex对象实例Match m = r.Match( "123abc456" ); // 在字符串中匹配if ( m.Success ) {
Console.WriteLine( "Found match at position " + m.Index ); //输入匹配字符的位置 }
int[] matchposition = new
int[20];
Regex r = new Regex( "abc" ); //定义一个Regex对象实例mc = r.Matches( "123abc4abcd" ); for (
int i = 0;
i < mc.Count;
i++ ) //在输入字符串中找到所有匹配 {
results[i] = mc[i].Value; //将匹配的字符串添在字符串数组中 matchposition[i] = mc[i].Index; //记录匹配字符的位置 }
2.4 GroupCollection 类表示捕获的组的集合
该集合为只读的,并且没有公共构造函数.GroupCollection 的实例在 Match.Groups 属性返回的集合中返回.下面的控制台应用程序查找并输出由正则表达式捕获的组的数目.
using System;
using System.Text.RegularExpressions;
public class RegexTest
{
public static void RunTest( )
{
Regex r = new Regex( "( a( b ) )c" ); //定义组 Match m = r.Match( "abdabc" );
Console.WriteLine( "Number of groups found = " + m.Groups.Count );
}
public static void Main( )
{
RunTest( );
}
}
该示例产生下面的输出:
Number of groups found = 3
2.5 CaptureCollection 类表示捕获的子字符串的序列
由于限定符,捕获组可以在单个匹配中捕获多个字符串.Captures属性(CaptureCollection 类的对象)是作为 Match 和 group 类的成员提供的,以便于对捕获的子字符串的集合的访问.例如,如果使用正则表达式 ( ( a( b ) )c )+(其中 + 限定符指定一个或多个匹配)从字符串"abcabcabc"中捕获匹配,则子字符串的每一匹配的 Group 的 CaptureCollection 将包含三个成员.
下面的程序使用正则表达式 ( Abc )+来查找字符串"XYZAbcAbcAbcXYZAbcAb"中的一个或多个匹配,阐释了使用 Captures 属性来返回多组捕获的子字符串.
using System;
using System.Text.RegularExpressions;
public class RegexTest
{
public static void RunTest( )
{
int counter;
Match m;
CaptureCollection cc;
GroupCollection gc;
Regex r = new Regex( "( Abc )+" ); //查找"Abc" m = r.Match( "XYZAbcAbcAbcXYZAbcAb" ); //设定要查找的字符串 gc = m.Groups; //输出查找组的数目 Console.WriteLine( "Captured groups = " + gc.Count.ToString( ) ); // Loop through each group. for (
int i=0;
i < gc.Count;
i++ ) //查找每一个组 {
cc = gc[i].Captures;
counter = cc.Count;
Console.WriteLine( "Captures count = " + counter.ToString( ) );
for (
int ii = 0;
ii < counter;
ii++ )
{ // Pr int capture and position.
Console.WriteLine( cc[ii] + " Starts at character " + cc[ii].Index ); //输入捕获位置 }
}
}
public static void Main( )
{
RunTest( );
}
}
此例返回下面的输出结果:
Captured groups = 2Captures count = 1AbcAbcAbc Starts at
character 3Captures count = 3Abc Starts at
character 3Abc Starts at
character 6Abc Starts at
character 9
2.6 Capture 类包含来自单个子表达式捕获的结果
在 Group 集合中循环,从 Group 的每一成员中提取 Capture 集合,并且将变量 posn 和 length 分别分配给找到每一字符串的初始字符串中的字符位置,以及每一字符串的长度.
Regex r;
Match m;
CaptureCollection cc;
int posn, length;
r = new Regex( "( abc )*" );
m = r.Match( "bcabcabc" );
for (
int i=0;
m.Groups[i].Value != "";
i++ )
{
cc = m.Groups[i].Captures;
for (
int j = 0;
j < cc.Count;
j++ )
{
posn = cc[j].Index; //捕获对象位置 length = cc[j].Length; //捕获对象长度 }
}
图1:对象关系
把组合字符组合起来后,每次都会返回一个组对象,就可能并不是我们希望的结果.如果希望把组合字符作为搜索模式的一部分,就会有相当大的系统开销.对于单个的组,可以用以字符序列"?:"开头的组禁止这么做,就像URI样例那样.而对于所有的组,可以在RegEx.Matches( )方法上指定RegExOptions.ExplicitCapture标志.
三.利用正则表达式实现字符串搜索
3.1 在C#中使用.NET一般表达式引擎
下面将通过一个样例的开发,执行并显示一些搜索的结果,说明一般表达式的一些特性,以及如何在C#中使用.NET一般表达式引擎.说明使用字符串时应在前面加上符号@.
String Text=@"I can not find my position in Beijing";
把这个文本称为输入字符串,为了说明一般表达式.NET类,本文先进行一次纯文本的搜索,这次搜索不带任何转义序列或一般表达式命令?俣ㄒ檎宜凶址甶on,把这个搜索字符串称为模式.使用一般表达式和上面声明的变量Text,编写出下面的代码:
String Pattern = "ion";
MatchCollection Matches = Regex.Matches( Text,Pattern,RegexOptions );
foreach( Match NextMatch in Matches )
{
Console.WriteLine( NextMatch.Index );
}
在这段代码中,使用了System.Text.RegularExpressions名称空间中Regex类的静态方法Match( ).这个方法的参数是一些输入文本、一个模式和RegexOptions每句中的一组可选标志.Matches( )返回MatchCollection,每个匹配都用一个Match对象来表示.在上面的代码中,只是在集合中迭代,使用Match类的Index属性,返回输入文本中匹配所在的索引.运行这段代码,将得到1个匹配项.
一般集合的功能主要取决于模式字符串.原因是模式字符串不仅仅包含纯文本.如前所述.还包含元字符和转义序列,元字符是给出命令的特殊字符,而转义序列的工作方式与C#的转义序列相同,它们都是以反斜杠开头的字符,具有特殊的含义.例如,假定要查找以n开头的字,就可以使用转义序列,它表示一个字的边界(字的边界是以某个字母数字标的字符开头,或者后面是一个空白字符或标点符号),下面编写如下代码:
String Pattern = @"n";
MatchCollection Matches = Regex.Matches( Text,Pattern,RegexOptions.IgnoreCase|RegexOptions.ExplicitCapture );
要在运行时把传递给.NET一般表达式引擎,反斜杠不应被C#编译器解释为转义序列.如果要查找以序列ion结尾的字,可以使用下面的代码:
String Pattern = @"ion";
如果要查找以字母n开头,以序列ion结尾的所有字,需要一个以n开头,以ion结尾的J?中间内容怎么办?需要告诉计算机n和ion中间的内容可以是任意长度的字符,只要字符不是空白即可,正确的模式如下所示:
String Pattern = @"nS*ion";
ECMAScript
无
指定已为表达式启用了符合 ECMAScript 的行为.此选项仅可与 IgnoreCase 和 Multiline 标志一起使用.将 ECMAScript 同任何其他标志一起使用将导致异常.
例如,Find_po在字开头处查找以"po"开头的字符串:
static void Find_po( )
{
string text = @" I can not find my position in Beijing ";
一般表达式的一个很好的特性是可以把字符组合起来,方式与C#中的复合语句一样.在C#中,可以通过把任意数量的语句放在花括号中的方式把它们组合在一起.其结果就像一个复合语句那样.在一般表达式模式中,也可以把任何字符组合起来(包括元字符和转义序列),像处理一个字符那样处理它们.唯一的区别是要使用圆括号,而不是花括号,得到的序列成为一个组.
例如,模式"( an )+"定位序列an的任以重复.量词+只应用于它前面的一个字符,但因为我们把字符组合起来了,所以它现在把重复的an作为一个单元来对待."( an )."应用到输入文本"bananas came to Europe late in the annals of history"上,会从bananas中选择出anan.另一方面,如果使用an+,则将从annals中选择ann,从bananas中选择出两个an.为什么(
an )+选择的是anan,而没有把单个的an作为一个匹配.匹配规则是不能重复的,如果有可能重复,在默认情况下就选择较长的匹配.
但是,组的功能要比这强大得多.在默认情况下,把模式的一部分组合为一个组时,就要求一般表达式引擎记住可以按照这个组来匹配,也可以按照整个模式来匹配.换言之,可以把组当作一个要匹配的模式,如果要把字符串分解为各个部分,这种模式就是非常有效的. 例如,URI的格式是"<protocol>://<address>:<port>",其中端口是可选的.它的一个样例是http://www.comprg.com.cn:8080?俣ㄒ右桓鯱RI中提取协议、地址和端口,而且紧邻URI的后面可能有空白(但没有标点符号),就可以使用下面的表达式:"(
S+ )://( S+ )( ?::( S+ ) )?" 该表达式的工作方式如下:首先,前导和尾部的序列确保只需要考虑完全是字的文本部分,在这个文本部分中,第一组"( S+ )://"会选择一个或多个不适空白的字符,其后是"://".在HTTPURI的开头会选择出http://.花括号表示把http存储为一个组.后面的"(
S+ )"则在上述URI中选择www. comprg.com.cn,这个组在遇到词的结尾时或标记另一个组的冒号"( : )"时结束. 下一个组选择端口(本例是:8080).后面的?表示这个组在匹配中是可选的,如果没有:xxxx,也不会妨碍匹配的标记.
这是非常重要的,因为端口在URI中一般不指定,实际上,在大多数情况下,URI是没有端口号的.但是,事情会比较复杂.如果要求冒号可以出现,也可以不出现,但不希望把这个冒号也存储在组中.为此,可以嵌套两个组:内部的"( S+ )"组选择冒号后面的内容(本例中是8080),外面的组包含内部的组,后面是一个冒号,该冒号又在序列"?:"的后面.这个序列表示该组不应保存(只需要保存"8080",不需要保存":8080").不要把这两个冒号混淆了,第一个冒号是序列"?:"的一部分,表示不保存这个组,第二个冒号是要搜索的文本.
在这个字符串上运行该模式:I always visit http://www. comprg.com.cn 得到的匹配是http://www. comprg.com.cn.在这个匹配中,仅提到了三个组,还有第四个组表示匹配本身.理论上,每个组都可以选择0次、1次或者多次匹配.单个的匹配就称为捕获.在第一个组"( S+ )",有一个捕获http.第二个组也有一个捕获www. comprg.com.cn,但第三个组没有捕获,因为在这个URI中没有端口号.注意该字符串在其本身上包含第二个http://.虽然它匹配于第一个组,但不会被搜索出来,因为整个搜索表达式不匹配于这部分文本.再比如下面这个例子,以下代码示例使用
Match.Result 来从 URL提取协议和端口号.例如,"http://www.yahoo.com.cn:8080/index.html"将返回"http:8080".
String Extension( String url )
{
Regex r = new Regex( @"^( ?<proto>w+ )://[^/]+?( ?<port>:d+ )?/", RegexOptions.Compiled ); return r.Match( url ).Result( "$ {
proto
}
$
{
port
} " );
}
四.总结
.NET 框架正则表达式类是基类库的一部分,并且可以和面向公共语言运行库的任何语言或工具(包括 asp.NET 和 Visual Studio .NET)一起使用.本文给出了在C#下利用正则表达式实现字符串搜索功能的方法,通过对.NET框架下的正则表达式的研究及实例分析,总结了正则表达式的规则、选项等,方便以后朋友们的应用