详解Visual Studio正则替换大法
某天,我遇到一堆这样的代码:
大家都看出来了,发现两个问题:
1. 检查是否为空的部分不是太合理;
2. DataReader使用索引的方式很难维护,要是查询增加字段,那就只能在后面增加了。
团队中有人重写了DataReader的方法,改进了这两点,就是使用rdr.GetInt32(“ID”)这种使用字段名的访问方式访问数据,另外还有一个重载,rdr.GetInt32(“ImageNumber”,0)这种为Null情况下赋默认值的操作,现在我们就要开始对代码就行重构。
发现一个问题,直接用Find & Replace肯定不行,因为里面即有相同点,又有不同点,最主要的不同就是每一行的Index参数都不同。
于是开始在Replace的Find Options里面找线索,发现最下方有一个Use,选中后可以选Regular Expressions和Wildcards。Wildcards其实是类似于系统的文件搜索方式,用“*”匹配任意文本,由于不在本文今天的讨论范围之内,就不赘述了。
正则表达式相信大家都很熟悉了,但这里的正则和以往大家所熟悉的正则有点不同,语法上有点不同,他是专门用于Visual Studio的,详细情往下看。
我们先开始搜索吧,先采集一段样本,直接复制“ID = rdr.GetValue(0) == DBNull.Value ? 0 : rdr.GetInt32(0)”到Find What输入框中,点击Find Next,发现提示“:”未知。
大家都想到了,正则中,很多符号都有自己定义的意思的,而我们这里不用他在正则中的意思,而是要搜索这个符号,所以我们要在有些符号前加上转义符
“\”,变成“ID = rdr\.GetValue\(0\) == DBNull.Value ? 0 \: rdr\.GetInt32\(0\)”,话说有人就要问了,“=”和“?”怎么就不用呢?难道没有意思么?我的回答是:请参考http://msdn.microsoft.com/en-us/library/2k3te2cs.aspx 。其实也不用那么麻烦,直接点输入框右边的三角,就可以得到常用的符号列表:
现在点击FindNext,发现已经能找到第一条符合的了,现在我们要抽取公共的部分,改写变化的部分,我们发现其实就是第一个部分的属性名和两个Index参数以及一个默认值三部分是变化的,我们将FindWhat改写为:“:i=rdr\.GetValue\(:z\)==DBNull.Value?:z\:rdr\.GetInt32\(:z\)”,其中,:i表示Identifier,:z表示Integer。
现在我们再点击FindNext发现找到了,再点一下,发现问题了,还是这句,只是开头的变量名被高亮的部分少了一个字符,发现问题就要解决啊!我们为:i加上单词边界符”<“和”>”,整句就变成”<:i>=rdr\.GetValue\(:z\)==DBNull.Value?:z\:rdr\.GetInt32\(:z\)”,再点FindNext。发现终于成功了。
以上是查找部分,你会了么?接下来就要进行我们激动人心的替换了!
我总结了一句话:用"{}"包围起不变的变化,用"\index"恢复她
解释一下,什么叫不变的变化呢?就如以上所示的“<:i>”,他是一个变量,每一行的都不同,所以他是变化的,而替换后的结果要求这些变化要保留,就是变量名替换后还是原来的。
比如:ID=xxxx;
Name=xxxx;
替换后要为:ID=yyyy;
Name=yyyy;
好!现在开始实施这句话,将”<:i>”变为”<{:i}>“。因为索引值是要抛弃的,而默认值是要保留的,所以整句话就变成<{:i}>=rdr\.GetValue\(:z\)==DBNull.Value?{:z}\:rdr\.GetInt32\(:z\)。
在ReplaceWith当中,我们写上要替换成的语句!注意:在ReplaceWith中,因为不需要进行正则查找,所以符号可以直接输,不用“\”转义,但”\”别有他用,用”\index”表示搜索式中被标记的第index个内容,index从1开始,"\0“表示搜索到的原内容。所以我们的ReplaceWith填\1=rdr.GetInt32("\1",\2)开始替换。
替换前:
替换后:
大家可能发现了,只替换了一部分GetInt32的,还有一堆GetString的,这里就留给大家去研究了!
我总结一下今天我们搜索条件的变化,给大家一个明显的思路提示。
1.取样:ID=rdr.GetValue(0)==DBNull.Value?0:rdr.GetInt32(0)
2.转义:ID=rdr\.GetValue\(0\)==DBNull.Value?0\:rdr\.GetInt32\(0\)
3.抽象::i=rdr\.GetValue\(:z\)==DBNull.Value?:z\:rdr\.GetInt32\(:z\)
4.缩范:<:i>=rdr\.GetValue\(:z\)==DBNull.Value?:z\:rdr\.GetInt32\(:z\)
5.标记:<{:i}>=rdr\.GetValue\(:z\)==DBNull.Value?{:z}\:rdr\.GetInt32\(:z\)