摘要:在VS 2012编辑器中使用正则表达式,可以有效提高开发效率。
一、这个帖子说的啥?
现在要说的是正则表达式。我们不去抠它的定义,也先不管那些严格而且琐碎的格式,而是看看怎么用。
大体来说,在.NET环境中进行开发时,有两个地方会用到正则表达式,一是用VS 2012进行编辑时,可以利用正则表达式进行查找和替换;二是代码中可以利用.NET提供的API,使用正则表达式的功能。
本文中说说第一种场景。我们通过几个例子看看怎么用正则表达式。
二、怎么查找包含回车换行的内容?
看下面的代码片段:
anObjectWithLongName.MethodAlsoWithLongName( 1,"blabla",...);
现在想要查找第一个参数为1时调用函数MethodAlsoWithLongName的地方。而由于对象名字和函数名字都太长,参数跑到了另外一行:和函数名不在一行上。
如果用Word,我们可以使用特殊字符^P,但VS 2012没有^P这样的特殊字符。怎么办呢?这时可以使用正则表达式。
首先按下Ctrl+Shift+F,表示在文件中查找,操作界面如下图所示:
首先选中“使用正则表达式”,然后在查找内容中输入:
MethodAlsoWithLongName\(\r\n1,
其中 MethodAlsoWithLongName 是我们要查找的函数名,1是要查找的参数,神奇的地方在于其中的\r\n,这在正则表达式中代表回车换行,相当于Word中的特殊字符^P。
另外注意其中的左括号前面加了反斜杠,这是因为左括号是正则表达式中的运算符,当我们真的需要左括号时,在前面加上反斜杠进行转义。
三、怎么查找符合指定格式的内容?
上面的例子中,\r\n是正则表达式的特殊字符,小括号是正则表达式的运算符,这些都属于正则表达式的基本知识。要使用正则表达式,还不得不掌握它们。好在MSDN中有详细介绍,网上也很容易查到。
我们继续举例子。话说有人写了这样的代码:
DataTable table = ...; DataRow row = table.Rows[0]; ... string desc = row["desc"].ToString(); string name = row["name"].ToString(); string userId = row["id"].ToString(); ...
我们对这样的代码不放心,因为row[colName]可能会返回空值,这时调用ToString()会引发空指针异常。我们想看看有多少处这样调用。(顺便说一下,我认为应当尽量少用DataTable,只在必要的地方才用它,例如数据库等的外部接口交互,在程序内部要设法避免。这属于结构化思路上的问题,以后再专门讨论。)
那么,我们的查询条件中,row[""].ToString()是固定的,但引号内的内容是不确定的。
这时仍使用正则表达式进行查找。操作和上个例子类似,只是查找条件不同,这一次是:
row\[".*"\]\.ToString\(\)
其中的固定部分是row[""].ToString(),但由于[,],.,(,)都是正则表达式的运算符,因此,都做了转义。
注意其中的红色粗体部分:.*,.表示任意字符,*表示任意多个,没有也符合。
四、怎么用正则表达式进行替换
继续上面的例子,我们总是不放心那样的做法,要做判空处理:列值不空的时候,才转换为字符串。对每次调用都这样处理,显然很繁琐。自然的做法是提取一个函数:
public static class Utils { public static string GetString(this DataRow row,string columnName) { return row.IsNull(columnName) ? string.Empty : row[columnName].ToString(); } }
这样上面的三行可以修改成:
... string desc = row.GetString("desc"); string name = row.GetString("name"); string userId = row.GetString("id"); ...
如果这样的调用很少,例如,只有这么三行,那么手工修改也就是了。但是如果很多,比如有几十上百处,一行行修改会让人崩溃。这时,正则表达式又可以派上用场了。
在使用正则表达式替换时,我们要清楚三个方面的内容:
1、替换的固定部分和可变部分
将 string desc = row["desc"].ToString(); 替换为 string desc = row.GetString("desc"); ,其中的row、前后两个desc是可变部分,其余是固定部分。其中固定部分就用原来的内容,可变部分要用.*那样的通配符。
查找的内容就是:string.* = .*\[".*"\]\.ToString\(\);
2、怎么提取原文中的可变部分
原文中的desc、row等内容还要用到,因此,需要从原文中提取出来,放到目标字符串中。怎么提取?这要用到正则表达式的“分组(Grouping)”概念(我现在也没有搞清楚为啥这么叫),将内容放到一个组中,就可以提取了。
在我们的例子中,所有可变内容都是需要的,因此,把它们都放到分组中。这样,查找的内容就变成了:string(.*) = (.*)\["(.*)"\]\.ToString\(\);
3、在目标字符串中怎么引用原文的可变部分
可以用分组序号引用,编号从1开始,用$加上序号,表示要获得分组的内容。上例中,$1表示变量名(如第一个desc),$2表示变量row,$3表示列名(第二个desc)。
这样,替换的目标字符串就是 string$1 = $2.GetString("$3");
替换的界面是这个样子的:
五、总结
没啥好总结的,利用正则表达式,就是可以提高效率。将几十、上百次重复劳动这样的体力活(真要做起来,多么苦逼啊~),改为脑力劳动,几下搞定!