- 浏览: 289674 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
全站唯一是我么:
请问下该功能的jdk版本是1.4的么,还是以上的?
Java实现给图片添加水印 -
Janne:
请问,你解决这问题没?是怎么回事?我今天也遇到了,没解决
myeclipse6.5中使用jax-ws启动tomcat报错问题 -
xuedong:
studypi 写道你是怎么和新浪的技术联系的?能告诉一下我吗 ...
新浪微博第三方接口调用学习 -
studypi:
你是怎么和新浪的技术联系的?能告诉一下我吗,谢谢
新浪微博第三方接口调用学习 -
dove19900520:
有用,呵呵
IE,Firefox都不放弃(兼容性问题总结)
1 概述
一般的正则替换,只能对匹配的子串做简单的处理,且只能是做string类型的处理之后,作为替换文本替换匹配子串,可以实现的功能比较有限。.NET的Replace()方法中的replacement参数,不仅可以是字符串,还可以是委托(delegate),在每次匹配成功时,都会调用委托方法,对匹配的子串进行处理之后,再作为替换文本返回,匹配子串使用委托方法,可以做任意复杂的处理,因此这种替换功能非常强大。
委托的类型可以是MatchEvaluator,也可以是匿名方法,在每次匹配成功时调用。委托方法传入参数是Match对象,返回类型是string,即正则表达式在每次匹配成功时,会得到一个Match对象,作为参数传给委托方法,做一定处理后,返回替换文本,替换匹配到的子串。
2 委托和匿名方法
在正则替换中使用的委托,一般有两种方式,显式声明的委托和匿名方法。下面以实例说明两种方式的使用方法。委托和匿名方法的区别和各自的特点不在这里介绍,请参考相关文献或文章。
2.1 委托
举例:
源字符串: a=10, b=20, c=30
需求:将字符串中的数字加100。
//委托方法
private string regReplace(Match m)
{
return (Convert.ToInt32(m.Value) + 100).ToString();
}
//声明一个MatchEvaluator类型委托
MatchEvaluator me = new MatchEvaluator(regReplace);
//正则替换应用
string test = "a=10, b=20, c=30";
Regex reg = new Regex(@"(?i)(?<=[a-z]=)/d+");
string result = reg.Replace(test, me);
richTextBox2.Text = result;
/*--------输出--------
a=110, b=120, c=130
*/
2.2 匿名方法
事实上,对于以上这种简单的需求,不需要显式的声明委托,直接使用匿名方法即可,
string test = "a=10, b=20, c=30";
Regex reg = new Regex(@"(?i)(?<=[a-z]=)/d+");
string result = reg.Replace(test, delegate(Match m) { return (Convert.ToInt32(m.Value) + 100).ToString(); });
richTextBox2.Text = result;
/*--------输出--------
a=110, b=120, c=130
*/
3 正则中委托的典型应用场景
一个涉及到替换的需求,首先要进行分析,是否能够通过一个正则表达式进行直接替换,如果不可以,那就要借助委托了。接下来就要找出可在委托方法中进行处理的子串的规律,剩下的就是委托方法中最基本的字符串处理了。
正则中委托的典型应用场景一般可归纳为以下几种:
1、替换子串需进行非string类型的处理,如计算等;
2、替换子串需经过条件或逻辑判断来决定处理方式;
3、多种条件组合的替换。
以上分类方式或许有重叠的地方,但是都比较有代表性,所以单独进行举例说明。
3.1 非string类型处理
替换子串非string类型处理,最典型的就是以上举例中的计算。还有比较典型的就是涉及计数的问题。
举例:
源字符串:<a href="http://www.sina.com.cn/">新浪 </a> <a href="http://www.sohu.com/">搜狐 </a> <a href="http://www.qq.com/">腾讯QQ </a> <a href="http://www.163.com/">网易163 </a>
需求:在每个链接后面加编号,结果
<a href="http://www.sina.com.cn/">新浪 </a>01 <a href="http://www.sohu.com/">搜狐 </a>02 <a href="http://www.qq.com/">腾讯QQ </a>03 <a href="http://www.163.com/">网易163 </a>04
代码实现:
string test = "<a href=/"http://www.sina.com.cn//">新浪</a><a href=/"http://www.sohu.com//">搜狐</a><a href=/"http://www.qq.com//">腾讯QQ</a><a href=/"http://www.163.com//">网易163</a>";
Regex reg = new Regex(@"(?is)<a[^>]*>(?:(?!</?a/b).)*</a>");
int i = 1;
string result = reg.Replace(test, delegate(Match m) { return m.Value + (i++).ToString("00"); });
richTextBox2.Text = result;
/*--------输出--------
<a href="http://www.sina.com.cn/">新浪</a>01<a href="http://www.sohu.com/">搜狐</a>02<a href="http://www.qq.com/">腾讯QQ</a>03<a href="http://www.163.com/">网易163</a>04
*/
这个需求是在链接后加编号,只要匹配到<a…>…</a>标签,在后面加上编号即可,但是由于编号是要根据a标签的个数来计数的,所以是动态变化的,这样直接替换就做不到了。而正则中的委托,是每次匹配成功后都会调用委托方法,而匹配是从左向右按顺序匹配的,所以调用委托方法也是按匹配的先后顺序进行调用的,这样就可以先用正则匹配出a标签,然后在委托方法中动态进行计数了。
3.2 逻辑判断
如果待替换的子串,需要根据当前匹配子串的内容,经过判断后决定如何替换,一般无法直接通过replace()实现,需求在委托方法里进行判断。
举例1:
源字符串:源字符串规律为“字母=数字”,用“&”相连
a=12&b=34&c=56&d=78
a=98&b=76&d=54
需求:如果源字符串有“c=数字”,就替换为“c=12”,否则在字符串结尾添加“&c=98”。
代码实现:
string[] test = new string[]{"a=12&b=34&c=56&d=78", "a=98&b=76&d=54"};
Regex reg = new Regex(@"(?is)(?<=^(?:(?!c=).)*)(?(c=[^&]+)c=[^&]+|$)");
foreach(string s in test)
{
richTextBox2.Text += "字符串: " + s + "/n";
richTextBox2.Text += "替换后: " + reg.Replace(s, delegate(Match m) { return m.Value == "" ? "&c=98" : "c=12"; }) + "/n/n";
}
/*--------输出--------
字符串: a=12&b=34&c=56&d=78
替换后: a=12&b=34&c=12&d=78
字符串: a=98&b=76&d=54
替换后: a=98&b=76&d=54&c=98
*/
还有一个类似的需求实例。
举例2(一个可能很简单的正式表达式求助):
源字符串:要处理的字符有可能是
""(空)
"p=1"
"ID=e2798a59&xx=79d5&bb=4833-9c57&cc=87d46a8&bb=b907a"
"ID=e2798a59&xx=79d5&bb=4833-9c57&cc=87d46a8&bb=b907a&p=2"
"ID=e2798a59&xx=79d5&p=4&bb=4833-9c57&cc=87d46a8&bb=b907a"
需求:对上述任何一种字符串的可能,查找是否有p=x,如果找不到,为字符串加上"p=0" ,如果找到,还要得到x的值,让y=x+1之后,再把"p=y"替换之前的p=x。
代码实现:
string[] test = new string[] { "", "p=1", "ID=e2798a59&xx=79d5&bb=4833-9c57&cc=87d46a8&bb=b907a", "ID=e2798a59&xx=79d5&bb=4833-9c57&cc=87d46a8&bb=b907a&p=2", "ID=e2798a59&xx=79d5&p=4&bb=4833-9c57&cc=87d46a8&bb=b907a" };
foreach (string s in test)
{
richTextBox2.Text += "原始字符串: /t" + s + "/n";
richTextBox2.Text += "替换后字符串: /t" + Regex.Replace(s, @"(?is)p=(?<v>/d+)|(?<!p=/d+.*)$", delegate(Match m) { if (m.Groups["v"].Value != "") return "p=" + (Convert.ToInt32(m.Groups["v"].Value) + 1); return "p=0"; }) + "/n/n";
}
/*--------输出--------
原始字符串:
替换后字符串: p=0
原始字符串: p=1
替换后字符串: p=2
原始字符串: ID=e2798a59&xx=79d5&bb=4833-9c57&cc=87d46a8&bb=b907a
替换后字符串: ID=e2798a59&xx=79d5&bb=4833-9c57&cc=87d46a8&bb=b907ap=0
原始字符串: ID=e2798a59&xx=79d5&bb=4833-9c57&cc=87d46a8&bb=b907a&p=2
替换后字符串: ID=e2798a59&xx=79d5&bb=4833-9c57&cc=87d46a8&bb=b907a&p=3
原始字符串: ID=e2798a59&xx=79d5&p=4&bb=4833-9c57&cc=87d46a8&bb=b907a
替换后字符串: ID=e2798a59&xx=79d5&p=5&bb=4833-9c57&cc=87d46a8&bb=b907a
*/
这个需求中,既涉及到了对替换子串的逻辑判断,又涉及到了数字运算,直接替换做不到,所以要考虑使用委托。先通过正则匹本出p=x,再在委托方法中进行逻辑判断和运算。
3.3 多条件组合替换
当需求中的条件多于一个时,可能无法在一个正则表达式中进行判断,或者即使能够在一个正则表达式中判断,由于正则表达式非常复杂,会降低匹配效率,所以还是要在委托方法中进行替换。
举例1:
源字符串:第一个测试...<a href=/"www.test.com/">又一个测试</a>...第三个测试...<a href=/"www.test.com/" title=/"测试/" >第几个测试了?</a>...这是最后一个测试了...
需求:为字符串中的“测试”加链接,已有链接的不加。
这个需求,首先是要进行替换,但又加了一个附加条件,已有链接的不替换,这样如果在一个正则表达式中实现,正则太复杂,不但降低匹配效率,扩展起来也很困难,可读性也差,所以还是用正则委托来实现比较好。
先分析一下需求,在<a…>…</a>标签内的关键字不进行替换,那换个角度,只要先找出a标签外的字符串,对关键字进行替换就可以满足需求了。所以就是写正则,匹配出a标签外的子串,在委托方法中对关键字加链接,再替换回原字符串就可以了。
代码实现:
string test = "第一个测试...<a href=/"www.test.com/">又一个测试</a>...第三个测试...<a href=/"www.test.com/" title=/"测试/" >第几个测试了?</a>...这是最后一个测试了...";
Regex reg = new Regex(@"(?is)^((?!</?a).)+|</a>((?!</?a).)+");
string result = reg.Replace(test, delegate(Match m) { return m.Value.Replace("测试", "<a href=/"www.test.com/">测试</a>"); });
richTextBox2.Text = result;
/*--------输出--------
第一个<a href="www.test.com">测试</a>...<a href="www.test.com">又一个测试</a>...第三个<a href="www.test.com">测试</a>...<a href="www.test.com" title="测试" >第几个测试了?</a>...这是最后一个<a href="www.test.com">测试</a>了...
*/
当然,这个例子并不严谨,因为其它标签中也可能出现关键字,而这些关键通常也是不应该被替换的,这时也可以在委托方法中进行判断,以确定是否应该被替换。
举例2(正则去除不包含特定字符串的A标签~):
源字符串:<a href=www.abc.com>abc </a>啊啊啊 <a href=bcd.com>abc </a>啊啊啊 <a href="www.abc.com" class="t1">abc </a>啊啊啊 <a href=def.com>abc </a>啊啊啊 <a href=efg.com>abc </a>
需求:把链接中不包含“abc”的超链接过滤掉。
这个需求,实际上也是两个条件,首先是要做替换,然后附加了一个条件,链接中不包含“abc”的替换。类似于这种符合某一规律的子串,部分替换,部分保留的情况,通常比较适合用正则委托来解决。
当然,这个需求还是可以直接通过一个正则表达式来处理的,先看一下这种处理方式的代码。
string test = "<a href=www.abc.com>abc </a>啊啊啊 <a href=bcd.com>abc </a>啊啊啊 <a href=/"www.abc.com/" class=/"t1/">abc </a>啊啊啊 <a href=def.com>abc </a>啊啊啊 <a href=efg.com>abc </a> ";
Regex reg = new Regex(@"(?is)<a(?:(?!href=).)*href=(['""]?)(?:(?!abc|['""/s>]).)+/1(?:/s[^>]*)?>((?:(?!</?a/b).)*)</a>");
string result = reg.Replace(test, "$2");
richTextBox2.Text = result;
/*--------输出--------
<a href=www.abc.com>abc </a>啊啊啊 abc 啊啊啊 <a href="www.abc.com" class="t1">abc </a>啊啊啊 abc 啊啊啊 abc
*/
可以看到,这种处理方式,是先进行判断,再进行匹配。在正则表达式中,对链接子串的每一个字符用“(?!abc|['""/s>]).”进行判断,所以有多少个字符,就要判断多少次,在这种情况下,通常需要使用“|”来对不同的条件取“或”,而“|”的效率一般是比较低的。
另一种处理方式,是先把链接匹配出来,然后在委托方法中进行判断,以决定是否替换。
代码实现:
string test = "<a href=www.abc.com>abc </a>啊啊啊 <a href=bcd.com>abc </a>啊啊啊 <a href=/"www.abc.com/" class=/"t1/">abc </a>啊啊啊 <a href=def.com>abc </a>啊啊啊 <a href=efg.com>abc </a> ";
Regex reg = new Regex(@"(?is)<a(?:(?!href=).)*href=(['""]?)([^'""/s>]+)/1[^>]*>((?:(?!</?a/b).)*)</a>");
string result = reg.Replace(test, delegate(Match m) { if (m.Groups[2].Value.IndexOf("abc") > -1) return m.Value; return m.Groups[3].Value; });
richTextBox2.Text = result;
/*--------输出--------
<a href=www.abc.com>abc </a>啊啊啊 abc 啊啊啊 <a href="www.abc.com" class="t1">abc </a>啊啊啊 abc 啊啊啊 abc
*/
这种处理方式,是先进行匹配,再进行判断。先通过正则把每一个链接都匹配出来,作为参数传给委托方法,在委托方法中判断是否包含“abc”,以决定是否替换。这种方式因为匹配过程中不需要进行判断,所以匹配的速度是很快的,然后在委托方法中只执行一次判断即可。两种处理方式的效率,在字符较少时区别不大,在字符较多,调用较频繁的情况下,还是委托方法的效率比较高。
类似于这种需求,在效率、可读性、可扩展性等方面综合考虑,还是使用委托方法要好一些。
转自:http://blog.csdn.net/lxcnn/article/details/4711491
发表评论
-
(从网上考过来的,收藏) javascript 正则表达式的贪婪与非贪婪
2012-10-08 10:35 850以下内容转自:http://www.cnitblog.com ... -
正则表达式常用验证
2011-08-24 12:20 832在前台很多地方需要验证输入格式,为了方便以后使用,把常用的整理 ... -
正则判断一个字符串里是否包含一些词
2011-08-16 16:53 3223今天项目里用到了正则,判断一个字符串里是不是包含这些词,词出 ... -
js取当前url参数
2011-07-19 11:14 1912js没有提供取当前url参数的方法,只能是自己从中截取了,在 ... -
正则手册
2011-07-07 16:53 997给大家共享个正则手册 欢迎查看本人博客: ... -
[ ] 字符组(Character Classes) .
2011-07-06 17:31 801[]能够匹配所包含的一系列字符中的任意一个。需要注意的是,[ ... -
正则基础之——捕获组(capture group) .
2011-07-06 17:30 9771 概述 1.1 什么是捕获组 ... -
正则表达式学习参考
2011-07-06 17:28 727正则表达式学习参考 1 ... -
正则基础之——小数点 .
2011-07-06 17:23 765小数点可以匹配除了换行符“/n”以外的任意一个字符 一 ... -
正则基础之——NFA引擎匹配原理 .
2011-07-06 17:22 973NFA引擎匹配原理 1 ... -
正则基础之——环视 .
2011-07-06 17:21 537环视只进行子表达式的匹配,不占有字符,匹配到的内容不保存到最终 ... -
正则基础之——/b 单词边界 .
2011-07-06 17:20 8031 概述 “/b”匹配单词边界,不匹配任何 ... -
正则应用之——日期正则表达式
2011-07-06 17:18 10231 概述 首先需要说明的一点,无论是Win ... -
.NET正则基础之——.NET正则匹配模式 .
2011-07-06 17:16 22891 概述 匹配模式指的是一些可以改变正则表 ... -
.NET正则基础之——平衡组 .
2011-07-06 17:14 17771 概述 平衡组是微软在.NET中提出的一 ... -
正则基础之——非捕获组 .
2011-07-06 17:10 1326非捕获组:(?:Expression) 接触正则表达式不久的 ... -
正则基础之——反向引用 .
2011-07-06 17:09 12751 概述 捕获组捕获到的内容,不仅可以在 ... -
.NET正则基础——.NET正则类及方法应用 .
2011-07-06 17:07 10791 概述 初学 ... -
正则基础之——贪婪与非贪婪模式 .
2011-07-06 17:03 9241 概述 贪婪 ... -
正则应用之——逆序环视探索
2011-07-06 17:01 11791 问题引出 前几天在CSDN论坛遇到这样 ...
相关推荐
1.4.35 Regex类——正则表达式 76 1.4.36 Split方法——分割字符串 78 1.4.37 String类——字符串 79 1.4.38 StringBuilder类——可变字符串 82 1.4.39 Substring方法——截取字符串 83 1.4.40 TimeSpan对象——表示...
第21天 01为什么会有委托 02泛型委托 03多播委托 04使用委托进行窗体传值 05事件 06事件 07程序集的引用 07Common 08反射的常用函数 09用反射制作计算器 第22天 01 SqlConnection 数据库 02...
实例4 TextBar控件应用举例——交通肇事申辩系统 实例5 使用正则表达式实现数据验证1 实例6 使用正则表达式实现数据验证2 实例7 Asp.net(C#)实现验证码功能 实例8 使用DataList建立一个留言板 ...
技术基础 New Folder 多样式星期名字转换 [Design, C#] .NET关于string转换的一个小Bug Regular Expressions 完整的在.net后台执行javascript脚本集合 ASP.NET 中的正则表达式 常用的匹配正则表达式和实例 经典正则...
本讲将通过实例比较ASP.NET下的三种典型URL重写方案——ISAPI重写(使用开源组件IIRF),ASP.NET2.0内置的urlMappings和基于自定义HTTPModule的URL重写(使用NBear.Web中的UrlRewriteModule实现),并探讨URL重写中...
而C#是.NET的核心——.NET框架的“母语”,因此使用C#能够有效地开发基于.NET的应用程序。 本书以最新的.NET 3.5和Visual C# 2008为基础循序渐进地介绍了从入门到深入掌握Visual C# 2008所需的各个方面,包括...