使用正则表达式

来源:互联网 发布:淘宝商城童装女童 编辑:程序博客网 时间:2024/04/27 02:22

正则表达式(Regular expressions)是一套语法匹配规则,各种语言,如Perl .NetJava都有其对应的共享的正则表达式类库。在.Net中,这个类库叫做Regex

简单的说,Regex是从字符窗中查找匹配字符串的应用类。通过Regex,编程人员能够非常方便的从一段数据中提取自己所需要的数据信息。举一个简单的例子,让大家对Regex有个大概的了解:

                            Regex regex = new Regex(@"/d+");                                                

                            Match m = regex.Match("fox 9212gold");                                        

                            Console.WriteLine(m.Value.ToString());                                       

结果很明显,regex为我们找到了字符串”fox 9212gold”中的数字字符串,输出结果为”9212” .

       Regex有了一个基本的概念之后,我需要告诉你一个非常好的消息,那就是Regex可以为我们做的远不止这么一点点,他是一套功能非常强大语法匹配规则。当然,这里还有一个坏消息等着我们,那就是强大功能的语法规则自然需要大量纷繁复杂的keyword支持,这也为Regex的学习带来了极大的难度。想要真正掌握正则表达式,可不是几个sample能够全部揭示与说明的。

 

创建一个Regex对象

       Regex的构造函数有三种,在这里就不讨论默认构造函数了。另外两个构造函数中,一个构造函数接收正则表达式字符串作为入参,另一个以正则表达式字符串和RegexOptions作为入参。如:

Regex regex = new Regex("/w+$");

Regex regex = new Regex("/s+", RegexOptions.IgnoreCase | RegexOptions.Multiline);

RegexOptions可以为我们提供一些特殊的帮助,比如IgnoreCase能够在匹配是忽略大小写,Multiline能够调整^$的意义,改为匹配一行的开头和结尾。

上面我们构造了一个正则表达式,只不过我们还没有用它来做任何事情,马上我们就可以通过使用下面的几个方法,实现对字符串对象的操作了。

匹配字符串

       Regex有两个获取匹配的方法Match()Matches(),分别代表匹配一个,匹配多个结果。这里就用Matches来展示一下怎么使用Regex获取匹配字符串,并将其显示出来。

         public static void showMatches(string expression, RegexOptions option, string ms)                 

         {                                                                                                    

                   Regex regex = new Regex(expression, option);                                             

                   MatchCollection matches = regex.Matches(ms);                                           

                   //show matches                                                                                  

                   Console.WriteLine("////////////////----------------------------------////////////////");                     

                   Console.WriteLine(" string: /"{0}/"/r/n expression: /"{1}/"/r/n match result is:",             

                  ms, expression);                                                                                

                   foreach(Match m in matches)                                                          

                   {                                                                                                                        Console.WriteLine("match string is: /"{0}/", length: {1}",                       

                           m.Value.ToString(), m.Value.Length);                                            

                   }                                                                                           

                   Console.WriteLine("matched count: {0}", matches.Count);                                   

         }                                                                                                    

 

方法Matched通过比较入参字符串和正则表达式,找到所有符合的结果,并将结果作为MatchCollection传出来。这样,只要简单的遍历这个collection,就可以很快的获得所有的结果。

 

组的概念

 

       当你获得这样的一个字符串最后比分是:19/24”,你肯定希望有一个正则表达式,他不单能够找到形如 data1/data2的字符串,还应该能够直接把data1,data2作为单独的结果传送出来。否则你需要再对形如”19/24”的字符串进行分析,才能够顺利得到双方的比分。显然,正则表达式不会忽略这个问题,所以他增加了组的概念。你可以把一次搜索的结果分别放入不同的组中,并通过组名或者组的所以分别取得这些组的结果。比如上例,我们就可以用@”(/d+)/(/d+)”作为表达式。来看看结果吧:

                            Regex regex = new Regex(@"(/d+)/(/d+)");                                             

                            MatchCollection matches = regex.Matches(@"最后比分是:19/24");        

                            //show matches                                                                         

                            Console.WriteLine("////////////////----------------------------------////////////////");            

                            foreach(Match m in matches)                                                 

                            {                                                                                  

                                     //Console.WriteLine("match string is: /"{0}/", length: {1}",                                                 // m.Value.ToString(), m.Value.Length);                                 

                                     foreach(string name in regex.GetGroupNames())                      

                                     {                                                                        

                                               Console.WriteLine("/r capture group /"{0}/" value is:/"{1}/""        

                                              , name, m.Groups[name].Value);                                 

                                     }                                                                        

                            }                                                                                  

                            Console.WriteLine("matched count: {0}", matches.Count);                         

 

输出:

////////////////----------------------------------////////////////

 capture group "0" value is:"19/24"

 capture group "1" value is:"19"

 capture group "2" value is:"24"

matched count: 1

 

现在清楚了吧,Regex对象把匹配的结果放入组0中。同时,匹配的组信息也放入了对应的组中。组的名称在默认的情况下,是从1开始依次增加的整数。0作为保留名称,专门用于指示匹配的整个字符串。既然有默认情况这样的概念,自然也就意味着用户可以自定义组的名称。方法很简单,在组的前面加上:?<name>就可以了。好了,现在把前面的正则表达式修改一下,换成@”(?<score1>/d+)/(?<score1>/d+)”,现在再看看结果:

////////////////----------------------------------////////////////

 capture group "0" value is:"19/24"

 capture group "score1" value is:"19"

 capture group "score2" value is:"24"

matched count: 1

 

换成自己定义的名字了吧,哈哈!为了在今后的测试中,能够更加方便的看到所有结果,我们对前面介绍过的showMatches()做一点小小的调整。这样,如果在表达式中包含了组的定义,我们也可以在不需要修改任何代码的情况下,直接看到所有的组信息了,调整后的方法showMatchesPro()如下:

         public static void showMatchesPro(string expression, RegexOptions option, string ms)          

         {                                                                                                    

                   Regex regex = new Regex(expression, option);                                             

                   MatchCollection matches = regex.Matches(ms);                                           

                   //show matches                                                                                  

                   Console.WriteLine("////////////////----------------------------------////////////////");                     

                   Console.WriteLine(" string: /"{0}/"/r/n expression: /"{1}/"/r/n match result is:",             

                  ms, expression);                                                                                

                   foreach(Match m in matches)                                                          

                   {                                                                                                                       foreach(string name in regex.GetGroupNames())                                

                            {                                                                                  

                                     Console.WriteLine("/r capture group /"{0}/" value is:/"{1}/"",                

                                     name, m.Groups[name].Value);                                            

                            }                                                                                  

                   }                                                                                           

                   Console.WriteLine("matched count: {0}", matches.Count);                                   

                   // show group name                                                                 

                  Console.WriteLine("group name count {0}", regex.GetGroupNames().Length);                 

                   foreach(string name in regex.GetGroupNames())                                         

                   {                                                                                           

                            Console.WriteLine("group name :/"{0}/"", name);                                 

                   }                                                                                           

         }                                                                                                    

 

替换字符串

Regex也提供了方便的匹配结果替换的功能。为了方便测试,我们也把他写成方法,代码如下:

        public static string replaceMatch(string expression, RegexOptions option, string ms, string rep)     

         {                                                                                                    

                   Regex regex = new Regex(expression, option);                                             

                   string result = regex.Replace(ms, rep);                                                  

                   Console.WriteLine("////////////////----------------------------------////////////////");                     

                   Console.WriteLine("string: /"{0}/", expression:/"{1}/", replace by : /"{2}/"",                    

                  ms, expression, rep);                                                                        

                   Console.WriteLine("replace result string is: /"{0}/", length: {1}",                                    

                                    result.ToString(), result.Length);                                            

                            return result;                                                                     

          }                                                                                                                                                                                                                

 

Regex.Replace通常接受两个string作为入参,第一个string为输入字符串。第二个字符串用来替代匹配字符串,它可以包含一些特殊字符串,用来代表特别转换。

 

特殊字符串                      替换结果

$&               匹配的字符串,也可以用$0

$1, $2, . . .    匹配字符串中的对应组,用索引标示

${name}      匹配字符串中的对应组,用名称标示

$‘              匹配位置之前的字符串

$’              匹配位置之后的字符串

$$         一个$字符

$_          输入字符串

$+         匹配字符串的所有组中,最后一个组中的数据

 

是不是看了这么多怪型怪状的特殊字符串,有点头晕了?嗯,那就弄两个sample来看看结果吧!

Sample1:

replaceMatch(@"/d+", RegexOptions.None, "fef 12/21 df 33/14   727/1", "<<$&>>");

输出,所有数字型的数据都被替换成了<<data>>

////////////////----------------------------------////////////////

string: "fef 12/21 df 33/14   727/1", expression:"/d+", replace by : "<<$&>>"

replace result string is: "fef <<12>>/<<21>> df <<33>>/<<14>>   <<727>>/<<1>>",

length: 50

 

Sample2:

replaceMatch(@"(/d+)/(/d+)", RegexOptions.None, "fef 12/21 df 33/14   727/1", "$+");

输出,所有data1/data2匹配的数据,都被替换成了data2

////////////////----------------------------------////////////////

string: "fef 12/21 df 33/14   727/1", expression:"(/d+)/(/d+)", replace by : "$+"

replace result string is: "fef 21 df 14   1", length: 16

 

怎么样,Regex的功能够丰富的吧!可是,也许你的需求不光这么简单,比如说,你要把”I have 200 dollars”中间的money加倍,怎么办?我晕倒,好像没有现成的东西可以用。没有关系,Regex还有更好的功能。它允许你自己定义转换公式。

using System.Text.RegularExpressions;                                                                  

class RegularExpressions                                                                                          

{                                                                                                              

   static string CapText(Match m)                                                                              

   {                                                                                                        

         // Get the matched string.                                                                           

         string x = m.ToString();                                                                               

         // double this value                                                                             

         string result = (int.Parse(x) * 2).ToString();                                                                

         return result;                                                                                        

   }                                                                                                            

   static void Main()                                                                                            

   {                                                                                                        

         string text = "i have 200 dollars";                                                                        

         string result = Regex.Replace(text, @"/d+",                                                              

         new MatchEvaluator(RegularExpressions.CapText));                                                     

         System.Console.WriteLine("result=[" + result + "]");                                                

   }                                                                                                        

}                                                                                                              

 

看看结果,太好了,我的钱真的变成了两倍!

但本文的目的是希望提供给大家一个方便好用的测试类,因此我们重载上面的repalceMatch方法,也允许自定义转换公式作为入参:

         public static string replaceMatch(string expression, RegexOptions option, string ms,               

                                    MatchEvaluator evaluator)                                                       

                   {                                                                                           

                            Regex regex = new Regex(expression, option);                                    

                            string result = regex.Replace(ms, evaluator);                                        

                            Console.WriteLine("////////////////----------------------------------////////////////");            

                            Console.WriteLine("string: /"{0}/", expression:/"{1}/", replace by a evaluator.", ms,    

                                                       expression);                                          

                            Console.WriteLine("replace result string is: /"{0}/", length: {1}", result.ToString(),     

                                                       result.Length);                                      

                            return result;                                                                     

                   }                                                                                           

 

拆分字符串

 

Regex还提供了从匹配位置将字符串拆分的方法Split。这个方法同样具有多个重载,不过这些都不是重点,大家可以自己看文档。我们继续完成我们用于测试的方法:

                   public static void splitMatch(string expression, RegexOptions option, string ms)              

                   {                                                                                           

                            Regex regex = new Regex(expression, option);                                    

                            string[] result = regex.Split(ms);                                                      

                            Console.WriteLine("////////////////----------------------------------////////////////");            

                            Console.WriteLine("string: /"{0}/", expression: /"{1}/", split result is:", ms,                  

                                               expression);                                                   

                            foreach(string m in result)                                                                

                            {                                                                                  

                                     Console.WriteLine("splited string is: /"{0}/", length: {1}",           

                                              m.ToString(), m.Length);                                       

                            }                                                                                  

                            Console.WriteLine("splited count: {0}", result.Length);                                 

                   }                                                                                           

代码简单,不多做解释。直接来一个smaple看看结果:

splitMatch(@"/",RegexOptions.None,  "2004/4/25");

输出:

////////////////----------------------------------////////////////

string: "2004/4/25", expression: "/", split result is:

splited string is: "2004", length: 4

splited string is: "4", length: 1

splited string is: "25", length: 2

splited count: 3

 

结果很明显,收工。

 

我的目的

写了这么多,回头一看,其实并没有怎么介绍正则表达式后的规则和keyword。不要着急,这不是重点。在文章的一开始,我就说了,正则表达式的规则太复杂了。就连MSDN也说了无法用一个表说明所有的表达式规则。我的目的很简单,介绍Regex的几个主要功能(匹配、替换和拆分),并提供几个简单方便的测试函数。让你能够测试你对正则表达式的理解是否准确。

 

比如想要确认^$的作用,你可以放入这样的(input, expression)数据:

(“123”, “^/d+$”)  (“123aaa456”, “^/d+”) (“123aaa456”, “123&”)

 

确认/d, /s, /w, /W的作用,可以这样测试:

(“123abc    gc 456”, “/d+”)(“123abc    gc 456”, “/s+”)

(“123abc    gc 456”, “/w+”)(“123abc    gc 456”, “/W+”)

 

比较? + *之间的区别可以用这样的数据:

(“a123 abcd”, “a/d?”) (“a123 abcd”, “a/d+”) (“a123 abcd”, “a/d*”)


原创粉丝点击