对代码中出现在注释里的 //TODO: 抽取出来,放在一个任务列表里,供开发者集中处理这些待办事项。这是在编程任务内部的个人日程管理。
VS 中已有此功能,但R# 做的更好,可以自定义这些项,让我最为心仪的是可以用.NET本身的正则表达式来定义这些项。
在VS中使用菜单 Resharper=>Options... 可以看到如下对话框:
选中"Note"项然后点击"Edit"按钮,或者在"Note"上直接双击,会弹出对话框来让你定义什么样的东西被识别为Note,至于怎么定义Note的显示颜色风格不是我关注的,那些东西一目了然。
关键在于这里的自定义正则表达式,我没找到R#在哪里说这个正则表达式是哪个流派的,因为正则表达式派系众多,所以<
>中文版中作者翻译为 Perl的正则流派, .NET的正则流派。。 是很贴切的。
在R#的论坛上,有人说起这个正则表达式,底下有人回帖说:
说话的 IIya Ryzhenkov 显然是R#的内幕人士。知道是哪个门派的就好对付了。
R# 自然是一流的C#开发助手,但在指定给NOTE的默认正则表达式这一点上,还有改进的余地。
上面的正则表达式可以这样解读:
首先,NOTE前面需要是一个“非word字符“, 或者位于”目标串“的开头,目标串是什么,暂时按下不表。接下来是定义关键字NOTE,并给它指定一个命名的捕获,NOTE之后要求是一个“非word字符"或行尾。其后可以是任何内容。
默认的正则表达式选项中代表任意字符的"."唯独不包括换行符,所以这个NOTE定义是只针对一行内容的
看下面它匹配到的例子:
贼没逮着,先把家丁给误打了。这是出现资源文件中的XML注释,可见R#对“注释”的理解是相当到位的,不光源代码中的注释,连相关技术中的注释也一并处理了。 这个显然我们不希望出现在TODO列表中,在一个实际项目中,这样的资源文件可不少呢,每一个资源文件就会多出这么一个干扰项来。下面使用正则表达式的断言功能来免除这一干扰。
(?! - application/x-microsoft.net.object) 就行了。这是一个右断言。
对默认的正则表达式,有以下几点可以改进的:
(1)试验表明,(?
NOTE)只是增加了可读性而已,R#并不处理匹配后的命名子模式。而设置一个命名捕获会增加正则表达式的运行开销。
(2)(\W|^)及(\W|$), (.*)这样的子模式都不必去捕获,捕获的子模式会增加正则表达式引擎的运行时开销。
(3)不必用\W这种费劲的方式
下面是重新指定的正则表达式:
所有对这里正则表达式的改进只有一个目的,就是让它尽可能快一点。下面是我修改后的正则表达式,除了让它快之外,还有让让它排除resx中微软的例行公事的Note,以及识别跨行的note的目的:
注意跨行NOTE只能是用 /* .. */这种注释形式的, 使用// 是达不到这个目的的。这是因为每一次R#尝试这个正则表达式来搜索NOTE的前提是它找到了一个“注释项”, 而使用// 的注释形式是每一个//就定义了一个单独的注释项。下一行的// 是另一个注释项了。
开头的(?s)实现了跨行。它让元字符"."能包括换行符
前面留下的话头是,R#拿什么样的目标字符串来让这个正则表达式去匹配? 我试验的结果,是R#会把作为注释的整个字符串(对于/*..*/格式的注释,还可能包括多行)前后的空白trim了之后的内容, 送给R#去匹配,所以如果你在正则表达式中使用\A表表示目标串的绝对开头, 它未必是//之后的第一个字符,如果//之后有任何空白,这些空白之后的第一个字符才是第一个字符。对于结尾部分的处理也是一样,在上面的正则表达式中简单加入$可以验证这一点。
string comment_str = GetNextCommentString();
string note_canidicate = comment_str.Trim(); // 去掉前后空白
if( re_note.IsMatch(note_canidicate) )
{
HightLightSpecialNoteComment(); //
}
Trim究竟去掉了哪些空白字符, 空格一定有(ASCII 0x20),TAB也一定有(ASCII 9), 还有其它的吗?
MSDN中对Trim的文档中说:
(PS:又是resharper提供的,知道我为什么这么推崇R#了吧)
且慢,什么是white-space字符呢,让我们把事做绝,祭出reflector(如果R#是C#开发的屠龙刀,reflector就是倚天剑,VS么,就是切菜板喽)。
public string Trim(params char[] trimChars)
{
if ((trimChars == null) || (trimChars.Length == 0))
{
trimChars = WhitespaceChars;
}
return this.TrimHelper(trimChars, 2);
}
|
不准备贴 TrimHelper的代码了,太长,它遍历一个叫 WhiteSpaceChars的静态字符数组,在字符串前后只要有字符是它所定义的空白字符,就移除。这个静态字符数组在string类的静态构造函数里定义:
看来往往随口一说的“空白字符”,在Unicode时代,不是仅仅空格+TAB 那么简单的,也不是C语言中对应的isspace 那么简单的,注意我们汉字空格也被包括在内了。由于字体的关系,在这里看不到全部的字符。
值得一提的是最后一个字符看似两个单引号直接连在了一起,其实是\uFEFF
数一数, 共有25个字符都被认为是空白字符。想知道那些庐山真面目难以看清的字符,可以通过 reflection很容易知道其 unicode(UTF16)编码:
public static void RunSnippet()
{
Type str_t = typeof(string);
FieldInfo fi = str_t.GetField("WhitespaceChars", BindingFlags.NonPublic | BindingFlags.Static);
char[] all_white_spaces = fi.GetValue(null) as char[];
foreach(char c in all_white_spaces)
{
WL("[{0}],{1}", c, (int)c );
}
WL( all_white_spaces.Length);
}
|
阅读(1550) | 评论(0) | 转发(0) |