Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2349326
  • 博文数量: 527
  • 博客积分: 10343
  • 博客等级: 上将
  • 技术积分: 5565
  • 用 户 组: 普通用户
  • 注册时间: 2005-07-26 23:05
文章分类

全部博文(527)

文章存档

2014年(4)

2012年(13)

2011年(19)

2010年(91)

2009年(136)

2008年(142)

2007年(80)

2006年(29)

2005年(13)

我的朋友

分类: WINDOWS

2008-11-21 18:07:39

对代码中出现在注释里的 //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) |
给主人留下些什么吧!~~