C#下利用正则表达式实现字符串搜索功能的方法.docx
- 文档编号:24137216
- 上传时间:2023-05-24
- 格式:DOCX
- 页数:15
- 大小:24.36KB
C#下利用正则表达式实现字符串搜索功能的方法.docx
《C#下利用正则表达式实现字符串搜索功能的方法.docx》由会员分享,可在线阅读,更多相关《C#下利用正则表达式实现字符串搜索功能的方法.docx(15页珍藏版)》请在冰豆网上搜索。
C#下利用正则表达式实现字符串搜索功能的方法
关键字:
正则表达式、元字符、字符串、匹配
1、正则表达式简介
正则表达式提供了功能强大、灵活而又高效的方法来处理文本。
正则表达式的全面模式匹配表示法可以快速地分析大量的文本以找到特定的字符模式;提取、编辑、替换或删除文本子字符串;或将提取的字符串添加到集合以生成报告。
对于处理字符串(例如HTML处理、日志文件分析和HTTP标头分析)的许多应用程序而言,正则表达式是不可缺少的工具。
.NET框架正则表达式并入了其他正则表达式实现的最常见功能,被设计为与Perl5正则表达式兼容,.NET框架正则表达式还包括一些在其他实现中尚未提供的功能,.NET框架正则表达式类是基类库的一部分,并且可以和面向公共语言运行库的任何语言或工具一起使用。
2、字符串搜索
正则表达式语言由两种基本字符类型组成:
原义(正常)文本字符和元字符。
正是元字符组为正则表达式提供了处理能力。
当前,所有的文本编辑器都有一些搜索功能,通常可以打开一个对话框,在其中的一个文本框中键入要定位的字符串,如果还要同时进行替换操作,可以键入一个替换字符串,比如在Windows操作系统中的记事本、Office系列中的文档编辑器都有这种功能。
这种搜索最简单的方式,这类问题很容易用String类的String.Replace()方法来解决,但如果需要在文档中识别某个重复的,该怎么办?
编写一个例程,从一个String类中选择重复的字是比较复杂的,此时使用语言就很适合。
一般表达式语言是一种可以编写搜索表达式的语言。
在该语言中,可以把文档中要搜索的文本、转义序列和特定含义的其他字符组合在一起,例如序列\b表示一个字的开头和结尾(子的边界),如果要表示正在查找的以字符th开头的字,就可以编写一般表达式\bth(即序列字符界是-t-h)。
如果要搜索所有以th结尾的字,就可以编写th\b(序列t-h-字边界)。
但是,一般表达式要比这复杂得多,例如,可以在搜索操作中找到存储部分文本的工具性程序(facility)。
3、.NET框架的正则表达式类
下面通过介绍.NET框架的正则表达式类,熟悉一下.NET框架下的正则表达式的使用方法。
3.1Regex类表示只读正则表达式
Regex类包含各种静态方法,允许在不显式实例化其他类的对象的情况下使用其他正则表达式类。
以下代码示例创建了Regex类的实例并在初始化对象时定义一个简单的正则表达式。
请注意,使用了附加的反斜杠作为转义字符,它将\s匹配字符类中的反斜杠指定为原义字符。
Regexr;//声明一个Regex类的变量
r=newRegex("\\s2000");//定义表达式
3.2Match类表示正则表达式匹配操作的结果
以下示例使用Regex类的Match方法返回Match类型的对象,以便找到输入字符串中第一个匹配。
此示例使用Match类的Match.Success属性来指示是否已找到匹配。
Regexr=newRegex("abc");//定义一个Regex对象实例
Matchm=r.Match("123abc456");//在字符串中匹配
if(m.Success)
{
Console.WriteLine("Foundmatchatposition"+m.Index);//输入匹配字符的位置
}
3.3MatchCollection类表示非重叠匹配的序列
该集合为只读的,并且没有公共构造函数。
MatchCollection的实例是由Regex.Matches属性返回的。
使用Regex类的Matches方法,通过在输入字符串中找到的所有匹配填充MatchCollection。
下面代码示例演示了如何将集合复制到一个字符串数组(保留每一匹配)和一个整数数组(指示每一匹配的位置)中。
MatchCollectionmc;
String[]results=newString[20];
int[]matchposition=newint[20];
Regexr=newRegex("abc");//定义一个Regex对象实例
mc=r.Matches("123abc4abcd");
for(inti=0;i { results[i]=mc[i].Value;//将匹配的字符串添在字符串数组中 matchposition[i]=mc[i].Index;//记录匹配字符的位置 } 3.4GroupCollection类表示捕获的组的集合 该集合为只读的,并且没有公共构造函数。 GroupCollection的实例在Match.Groups属性返回的集合中返回。 下面的控制台应用程序查找并输出由正则表达式捕获的组的数目。 usingSystem; usingSystem.Text.RegularExpressions; publicclassRegexTest { publicstaticvoidRunTest() { Regexr=newRegex("(a(b))c");//定义组 Matchm=r.Match("abdabc"); Console.WriteLine("Numberofgroupsfound="+m.Groups.Count); } publicstaticvoidMain() { RunTest(); } } 该示例产生下面的输出: Numberofgroupsfound=3 3.5CaptureCollection类表示捕获的子字符串的序列 由于限定符,捕获组可以在单个匹配中捕获多个字符串。 Captures属性(CaptureCollection类的对象)是作为Match和group类的成员提供的,以便于对捕获的子字符串的集合的访问。 例如,如果使用正则表达式((a(b))c)+(其中+限定符指定一个或多个匹配)从字符串"abcabcabc"中捕获匹配,则子字符串的每一匹配的Group的CaptureCollection将包含三个成员。 下面的程序使用正则表达式(Abc)+来查找字符串"XYZAbcAbcAbcXYZAbcAb"中的一个或多个匹配,阐释了使用Captures属性来返回多组捕获的子字符串。 usingSystem; usingSystem.Text.RegularExpressions; publicclassRegexTest { publicstaticvoidRunTest() { intcounter; Matchm; CaptureCollectioncc; GroupCollectiongc; Regexr=newRegex("(Abc)+");//查找"Abc" m=r.Match("XYZAbcAbcAbcXYZAbcAb");//设定要查找的字符串 gc=m.Groups; //输出查找组的数目 Console.WriteLine("Capturedgroups="+gc.Count.ToString()); //Loopthrougheachgroup. for(inti=0;i { cc=gc[i].Captures; counter=cc.Count; Console.WriteLine("Capturescount="+counter.ToString()); for(intii=0;ii { //Printcaptureandposition. Console.WriteLine(cc[ii]+"Startsatcharacter"+ cc[ii].Index);//输入捕获位置 } } } publicstaticvoidMain(){ RunTest(); } } 此例返回下面的输出结果: Capturedgroups=2 Capturescount=1 AbcAbcAbcStartsatcharacter3 Capturescount=3 AbcStartsatcharacter3 AbcStartsatcharacter6 AbcStartsatcharacter9 3.6Capture类包含来自单个子表达式捕获的结果 在Group集合中循环,从Group的每一成员中提取Capture集合,并且将变量posn和length分别分配给找到每一字符串的初始字符串中的字符位置,以及每一字符串的长度。 Regexr; Matchm; CaptureCollectioncc; intposn,length; r=newRegex("(abc)*"); m=r.Match("bcabcabc"); for(inti=0;m.Groups[i].Value! ="";i++) { cc=m.Groups[i].Captures; for(intj=0;j { posn=cc[j].Index;//捕获对象位置 length=cc[j].Length;//捕获对象长度 } } 把组合字符组合起来后,每次都会返回一个组对象,就可能并不是我们希望的结果。 如果希望把组合字符作为搜索模式的一部分,就会有相当大的系统开销。 对于单个的组,可以用以字符序列"? : "开头的组禁止这么做,就像URI样例那样。 而对于所有的组,可以在RegEx.Matches()方法上指定RegExOptions.ExplicitCapture标志。 4、利用正则表达式实现字符串搜索 4.1在C#中使用.NET一般表达式引擎 下面将通过一个样例的开发,执行并显示一些搜索的结果,说明一般表达式的一些特性,以及如何在C#中使用.NET一般表达式引擎。 说明使用字符串时应在前面加上符号@。 StringText=@"IcannotfindmypositioninBeijing"; 把这个文本称为输入字符串,为了说明一般表达式.NET类,本文先进行一次纯文本的搜索,这次搜索不带任何转义序列或一般表达式命令。 假定要查找所有字符串ion,把这个搜索字符串称为模式。 使用一般表达式和上面声明的变量Text,编写出下面的代码: StringPattern="ion"; MatchCollectionMatches=Regex.Matches(Text,Pattern,RegexOptions); foreach(MatchNextMatchinMatches) {Console.WriteLine(NextMatch.Index);} 在这段代码中,使用了System.Text.RegularExpressions名称空间中Regex类的静态方法Match()。 这个方法的参数是一些输入文本、一个模式和RegexOptions每句中的一组可选标志。 Matches()返回MatchCollection,每个匹配都用一个Match对象来表示。 在上面的代码中,只是在集合中迭代,使用Match类的Index属性,返回输入文本中匹配所在的索引。 运行这段代码,将得到1个匹配项。 一般集合的功能主要取决于模式字符串。 原因是模式字符串不仅仅包含纯文本。 如前所述。 还包含元字符和转义序列,元字符是给出命令的特殊字符,而转义序列的工作方式与C#的转义序列相同,它们都是以反斜杠\开头的字符,具有特殊的含义。 例如,假定要查找以n开头的字,就可以使用转义序列\b,它表示一个字的边界(字的边界是以某个字母数字标的字符开头,或者后面是一个空白字符或标点符号),下面编写如下代码: StringPattern=@"\bn"; MatchCollectionMatches=Regex.Matches(Text,Pattern,RegexOptions.IgnoreCase RegexOptions.ExplicitCapture); 要在运行时把\b传递给.NET一般表达式引擎,反斜杠\不应被C#编译器解释为转义序列。 如果要查找以序列ion结尾的字,可以使用下面的代码: StringPattern=@"ion\b"; 如果要查找以字母n开头,以序列ion结尾的所有字,需要一个以\bn开头,以ion\b结尾的模式,中间内容怎么办? 需要告诉计算机n和ion中间的内容可以是任意长度的字符,只要字符不是空白即可,正确的模式如下所示: StringPattern=@"\bn\S*ion\b"; 4.2特定字符或转义序列 大多数重要的正则表达式语言运算符都是非转义的单个字符。 转义符\(单个反斜杠)通知正则表达式分析器反斜杠后面的字符不是运算符。 例如,分析器将星号(*)视为重复限定符,而将后跟星号的反斜杠(\*)视为Unicode字符002A。 使用一般表达式要习惯的一点是,查看像这样怪异的字符序列,但这个序列的工作是非常逻辑化的。 转义序列\S表示任何不适空白的字符。 *称为数量词,其含义是前面的字符可以重复任意次,包括0次。 序列\S*表示任何不适空白的字符。 因此,上面的模式匹配于以n开头,以ion结尾的任何单个字。 下表中列出的字符转义在正则表达式和替换模式中都会被识别。 表1: 特定字符或转义序列 特定字符或转义序列含义样例匹配的样例 ^输入文本的开头^BB,但只能是文本中的第一个字符 $输入文本的结尾X$X,但只能是文本中的最后一个字符 .除了换行字符(\n)以外的所有单个字符i.ationisation、ization *可以重复0次或多次的前导字符ra*trat、raat等 +可以重复1次或多次的前导字符ra+trt、rat、raat等 ? 可以重复0次或1次的前导字符ra? t只有rt和rat匹配 \s任何空白字符\sa[space]a,\ta,\na(\t和\n与C#的\t和\n含义相同) \S任何不是空白的字符\SFaF,rF,cF,但不能是\tf \b字边界ion\b以ion结尾的任何字 \B不是字边界的位置\BX\B字中间的任何X 如果要搜索一个元字符,也可以通过带有反斜杠的转义字符来表示。 例如,.表示除了换行字符以外的任何字符,而\.表示一个点。 可以把可替换的字符放在方括号中,请求匹配包含这些字符。 例如,[1c]表示字符可以是1或者是c。 如果要搜索map或者man,可以使用序列"ma[np]"(仅指引号内字符,下面雷同)。 在方括号中,也可以制定一个范围,例如"[a-z]"表示所有的小写字母(使用连字号(-)允许指定连续字符范围),"[B-F]"表示B到F之间的所有大写字母,"[0-9]"表示一个数字,如果要搜索一个整数(该序列只包含0到9的字符),就可以编写"[0-9]+"(注意,使用+字符表示至少要有这样一个数字,但可以有多个数字,所以9、83和3443等都是匹配的。 ) 下面看看一般表达式的结果,编写一个实例RegularExpressionsZzy。 建立几个一般表达式,显示其结果,让用户了解一下表达式是如何工作的。 该实例的核心是一个方法WriteMatches(),它把MatchCollection中的所有匹配以比较详细的方式显示出来。 对于每个匹配,它都会显示该匹配在输入字符串中所在的索引,匹配的字符串和一个略长的字符串,其中包含输入文本中至多8个外围字符,其中至少有5个字符放在匹配的前面,至多5个字符放在匹配的后面(如果匹配的位置在输入文本的开头或结尾5个字符内,则结果中匹配前后的字符就会少于4个)。 换言之,靠近输入文本末尾的匹配应是"andmessagingofd",匹配的前后各有5个字符,但位于输入文本的最后一个字上的匹配就应是"gofdata",匹配的字后只有一个字符。 因为在该字符的后面是字符串的结尾。 这个长字符串可以更清楚地表明一般表达式是在什么地方查找到匹配的: staticvoidWriteMatches(stringtext,MatchCollectionmatches) { Console.WriteLine("Originaltextwas: \n\n"+text+"\n"); Console.WriteLine("No.ofmatches: "+matches.Count); foreach(MatchnextMatchinmatches) { intIndex=nextMatch.Index; stringresult=nextMatch.ToString(); intcharsBefore=(Index<5)? Index: 5; intfromEnd=text.Length-Index-result.Length; intcharsAfter=(fromEnd<5)? fromEnd: 5; intcharsToDisplay=charsBefore+charsAfter+result.Length; Console.WriteLine("Index: {0},\tString: {1},\t{2}",Index,result, text.Substring(Index-charsBefore,charsToDisplay)); } } 在这个方法中,处理过程是确定在较长的字符串中有多少个字符可以显示,而无需超限输入文本的开头或结尾。 注意在Match对象上使用了另一个属性Value,它包含标识该匹配的字符串,而且,RegularExpressionsZzy只包含名为Find_po,Find_n等的方法,这些方法根据本文执行某些搜索操作。 4.3正则表达式选项 可以使用影响匹配行为的选项修改正则表达式模式。 可以通过两种基本方法设置正则表达式选项: 其一是可以在Regex(pattern,options)构造函数中的options参数中指定,其中options是RegexOptions枚举值的按位"或"组合;其二是使用内联(? imnsx-imnsx: )分组构造或(? imnsx-imnsx)其他构造在正则表达式模式内设置它们。 在内联选项构造中,一个选项或一组选项前面的减号(-)用于关闭这些选项。 例如,内联构造(? ix-ms)将打开IgnoreCase和IgnorePatternWhiteSpace选项而关闭Multiline和Singleline选项。 表2: RegexOptions枚举的成员以及等效的内联选项字符 RegexOption成员内联字符说明 None无指定不设置任何选项。 IgnoreCasei指定不区分大小写的匹配。 Multilinem指定多行模式。 更改^和$的含义,以使它们分别与任何行的开头和结尾匹配,而不只是与整个字符串的开头和结尾匹配。 ExplicitCapturen指定唯一有效的捕获是显式命名或编号的(? ...)形式的组。 这允许圆括号充当非捕获组,从而避免了由(? : ...)导致的语法上的笨拙。 Compiled无指定正则表达式将被编译为程序集。 生成该正则表达式的Microsoft中间语言(MSIL)代码;以较长的启动时间为代价,得到更快的执行速度。 Singlelines指定单行模式。 更改句点字符(.)的含义,以使它与每个字符(而不是除\n外的所有字符)匹配。 IgnorePatternWhitespacex指定从模式中排除非转义空白并启用数字符号(#)后面的注释。 请注意,空白永远不会从字符类中消除。 RightToLeft无指定搜索是从右向左而不是从左向右进行的。 具有此选项的正则表达式将移动到起始位置的左边而不是右边。 (因此,起始位置应指定为字符串的结尾而不是开头。 )为了避免构造具有无限循环的正则表达式的可能性,此选项不能在中流指定。 但是,(? <)回顾后发构造提供了可用作子表达式的类似替代物。 ECMAScript无指定已为表达式启用了符合ECMAScript的行为。 此选项仅可与IgnoreCase和Multiline标志一起使用。 将ECMAScript同任何其他标志一起使用将导致异常。 例如,Find_po在字开头处查找以"po"开头的字符串: staticvoidFind_po() { stringtext=@"IcannotfindmypositioninBeijing"; stringpattern=@"\bpo\S*ion\b"; MatchCollectionmatches=Regex.Matches(text,pattern,RegexOptions.IgnoreCase RegexOptions.IgnorePatternWhitespaceRegexOptions.ExplicitCapture); WriteMatches(text,matches); } 这段代码还使用了名称空间RegularExpressions: usingSystem; usingSystem.Text.RegularExpressions; 4.4匹配、组和捕获 一般表达式的一个很好的特性是可以把字符组合起来,方式与C#中的复合语句一样。 在C#中,可以通过把任意数量的语句放在花括号中的方式把它们组合在一起。 其结果就像一个复合语句那样。 在一般表达式模式中,也可以把任何字符组合起来(包括元字符和转义序列),像处理一个字符那样处理它们。 唯一的区别是要使用圆括号,而不是花括号,得到的序列成为一个组。 例如,模式"(an)+"定位序列an的任以重复。 量词+只应用于它前面的一个字符,但因为我们把字符组合起来了,所以它现在把重复的an作为一个单元来对待。 "(an)."应用到输入文本"bananascametoEuropelateintheannalsofhistory"上,会从bananas中选择出anan。 另一方面,如果使用an+,则将从annals中选择ann,从bananas中选择
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C# 利用 正则 表达式 实现 字符串 搜索 功能 方法