今日随笔,继续写一点关于正则表达式的 知识。前两天介绍了正则表达式验证匹配,提取等一些基本的知识,今天继续分享下它的另一个强大的应用:替换(replace)。
开始之前,还是要补一下昨天的内容。
在我们昨天的内容里,有一个提取组的概念,在上一节中,我么只用了数值索引来获取某组的value。我们还可以给某个组取一个别名,然后通过别名来找到相应的组的value。
我们还拿昨天的name和age那个例子说明:
1 //----------------------------------通过数值索引------------------- 2 string regex = @"name=(\w+)age=(\d{0,2})"; 3 string str = "name=小强age=23"; 4 Match match = Regex.Match(str, regex); 5 6 Console.WriteLine("name:{0},age:{1}", match.Groups[1].Value, match.Groups[2].Value); 7 8 //输出结果 name:小强,age:23 9 //----------------------------------end------------------- 10
11 //-------------------------------------通过别名------------------------------ 12 string regex = @"name=(?<name>\w+)age=(?'age'\d{0,2})"; 13 string str = "name=小强age=23"; 14 Match match = Regex.Match(str, regex); 15 16 Console.WriteLine("name:{0},age:{1}", match.Groups["name"].Value, match.Groups["age"].Value); 17 Console.WriteLine("COUNT:" + match.Groups.Count); 18 for (int i = 0; i < match.Groups.Count; i++) 19 { 20 Console.WriteLine("{0}--------->{1}", i, match.Groups[i].Value); 21 } 22 23 //输出结果 name:小强,age:23 24 //COUNT:3 25 //0---------->name=小强age=23 26 //1---------->小强 27 //2---------->23
首先,要先说一下这是微软支持组别名的语法,在PHP,Python中,可以用(?P﹤name﹥group)来对组进行命名。词法?P﹤name﹥就是对组(group)进行了命名。其中name是你对组的起的名字。你可以用(?P=name)进行引用(一会会介绍引用这个东东)。
NET framework也支持命名组。不幸的是,微软的程序员们决定发明他们自己的语法,而不是沿用Perl、Python的规则。
(?﹤name﹥小强)(?’age’ 23),
如你所看到的,.NET提供两种词法来创建命名组:一是用尖括号“?﹤﹥”,或者用单引号“?'' ”。尖括号在字符串中使用更方便,单引号在ASP代码中更有用,因为ASP代码中“﹤﹥”被用作HTML标签。
恩。。。,今天还要补一组别名的另一个应用:“正则表达式组之重复操作与后向引用”
当用“()”定义了一个正则表达式组后,正则引擎则会把被匹配的组按照顺序编号,存入缓存。当对被匹配的组进行向后引用的时候,可以用“\数字”的方式进行引用。“\1”引用第一个匹配的后向引用组,“\2"引用第二个组,以此类推,"\n"引用第n个组。而"\0"则引用整个被匹配的正则表达式本身。我们看一个例子。
假设你想匹配一个HTML标签的开始标签和结束标签,以及标签中间的文本。比如﹤B﹥This is a test﹤/B﹥,我们要匹配﹤B﹥和﹤/B﹥以及中间的文字。我们可以用如下正则表达式:“﹤([A-Z][A-Z0-9]*)[^﹥]*﹥.*?﹤/\1﹥”
首先,“﹤”将会匹配“﹤B﹥”的第一个字符“﹤”。然后[A-Z]匹配B,[A-Z0-9]*将会匹配0到多次字母数字,后面紧接着0到多个非“﹥”的字符。最后正则表达式的“﹥”将会匹配“﹤B﹥”的“﹥”。接下来正则引擎将对结束标签之前的字符进行惰性匹配,直到遇到一个“﹤/”符号。然后正则表达式中的“\1”表示对前面匹配的组“([A-Z][A-Z0-9]*)”进行引用,在本例中,被引用的是标签名“B”。所以需要被匹配的结尾标签为“﹤/B﹥”
你可以对相同的后向引用组进行多次引用,([a-c])x\1x\1将匹配“axaxa”、“bxbxb”以及“cxcxc”。如果用数字形式引用的组没有有效的匹配,则引用到的内容简单的为空。
一个后向引用不能用于它自身。([abc]\1)是错误的。因此你不能将﹤﹤\0﹥﹥用于一个正则表达式匹配本身,它只能用于替换操作中。
代码如下:
string regex = @"name=(\w+),waihao=\1"; //string regex = @"([a-c])x\1x\1"; while (true) { string str = Console.ReadLine(); Console.WriteLine(Regex.IsMatch(str, regex)); }
//输入:name=小强,waihao=小强
//输出的是True
好啦,昨天的内容,就补到这,现在让我们看看正则表达式中替换的用法。
啥也不说,还是先上例子
#region 正则表达式字符串替换,将连续的a都替换成a ////1.你aaa好aa哈哈a你 //string msg = "你aaa好aa哈aaaaa哈a你"; //msg = Regex.Replace(msg, "a+", "a"); //Console.WriteLine(msg); //Console.ReadKey(); #endregion #region 练习2:将连续的-都替换成一个- //string msg = "234-----234--------------34------55"; //msg = Regex.Replace(msg, @"\-+", "-"); ////Regex.Split(); //Console.WriteLine(msg); //Console.ReadKey(); #endregion #region 替换案例:将hello 'welcome' to 'China' 替换成 hello 【welcome】 to 【China】 ////hello 【welcome】 to 【China】 ////'slslls' 【slslls】 //string msg = "hello 'welcome' to 'China'"; ////msg.Replace("'","】" //正则表达式的替换中也可以使用提取组,使用()来分组,使用$n,来引用提取组。 //msg = Regex.Replace(msg, "'(.+?)'", "【$1】"); //Console.WriteLine(msg); //Console.ReadKey(); #endregion
替换:顾名思义就是把一个字符串中,与正则表达式模式匹配的地方,给替换成我们想要的部分。用的是Regex的Replace方法。。。
Replace: 在指定的输入字符串内,使用指定的替换字符串替换与指定正则表达式匹配的所有字符串。返回结果:一个与输入字符串基本相同的新字符串,唯一的差别在于,其中的每个匹配字符串已被替换字符串代替。
在上面的三个例子中,前两个很简单了,我就不说了,有一点要注意的是”-“是元字符,所以要转义一下。
第三个例子我要说一下,这里要注意两点,一点事提取组的用法:例子中要把说有用引号包起来的地方都替换成 用【】包起来,那么我们先定义一个正则表达式模式regex='(.+?)',这里我们把引号之间的内容括了起来作为一个提取住,然后在replac方法的第三个参数中,我们可以用$1代替刚才那个提取组的内容(因为引号之间的内容是第一组,所以这里用的是$1)。同时,还要注意一点的就是在”.+“的后面加了一个问号,这就是我们前面所说的终止贪婪模式,如果不加得话,以为welcome' to 'China 都属于"."这个元字符的匹配的范围内,所以最终匹配的结果将会是hello 【welcome' to 'China】。
Repalce方法有一个重载,第三个参数是穿进去一个委托实例(方法),在这个方法中,你可以自己定义具体要怎么替换或者是做相应的操作,然后将string结果返回。这个就先不举例子了,在今后我会专门写一个委托的系列和大家分享。
好啦,再给大家上几个例子,正则表达式就告于段落了,这三篇文章知识讲了一些正则表达式的基本用法,和一些应用的列子(在这些应用中,有的正则表达式模式定义的不是很精确,比如上一节中匹配email,上上节中的匹配身份证等等,在这里主要的目的是举例子介绍正则表达式,而没有去写较精确的匹配模式),它还有更多的应用和用法,大家在工作中继续探讨和学习吧。
#region 手机号码隐去中间四位 //string msg = "我叫杨中科:13488888888我是苏坤18999141365。蒋坤:13111111111。"; //msg = Regex.Replace(msg, @"(\d{3})\d{4}(\d{4})", "$1****$2"); //Console.WriteLine(msg); //Console.ReadKey(); #endregion #region 练习1:将一段文本中的MM/DD/YYYY格式的日期转换为YYYY-MM-DD格式 ,比如“我的生日是05/21/2010耶”转换为“我的生日是2010-05-21耶”。 //string msg = "我的生日是05/21/2010耶,TA的生日是:06/09/2000,哦耶耶"; //msg = Regex.Replace(msg, @"(\d{2})/(\d{2})/(\d{4})", "$3-$1-$2"); //Console.WriteLine(msg); //Console.ReadKey(); #endregion //a+? //xaaaaaaaab #region 练习2:给一段文本中匹配到的url添加超链接,比如把http://www.test.com替换为<a href="http://www.test.com"> http://www.test.com</a>。 //string msg = "比如把http://www.test.com,新浪http://www.sina.com百度http://www.baidu.com网易:http://www.163.com。传智播客http://net.itcast.cn。"; //msg = Regex.Replace(msg, @"(http://[a-zA-Z0-9_\-\.&\?]+)", "<a href=\"$1\">$1</a>"); //Console.WriteLine(msg); //Console.ReadKey(); #endregion
恩。。给自己的博客做个广告吧,这段时间正在写一个关于asp.net运行机制的系列,希望更多的小伙伴们可以去给 出指点。
好啦,亲爱的小伙伴们,我们一起加油吧,坚信我的老师跟我说的一句话,写程序也是一种艺术,程序员是一名艺术家,而不是苦逼。 ^_^ Come On~~ GO!GO!.