posts - 4, comments - 0, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

2008年6月2日

    恐惧紧张的时候,手里总会紧紧抓着什么东西。也许是拼命抓着某人的手臂并躲在其身后;也许仅仅是使劲攥着一个小物事,比如说一根笔;也许什么也没抓到,只是紧紧握着拳头,仿佛抓着了什么东西。我看不清楚这些年我手里一直抓着的,是什么东西,我想也许只有松开拳头,才能真正面对所有的一切,然而我只是紧紧抓着这个不明物体。
    总觉得chandler身上可以看到自己的影子,因为据剧中人士分析,他也喜欢以幽默的方式和人保持距离。那位师侄居然开始说我长不大,不错,这也是我的方式之一。荒原也说我不自信,算她蒙对了,但她绝对想象不出这种不自信,是个什么样的形体。
    我在想我为什么迈不出去呢?这是一个玻璃罩着的完整体系,我若踩出去,势必踢坏玻璃罩,黑暗的海洋就涌了进来,于是乎我就从梦中惊醒。。
    我在想那个人是谁呢?为何有如此强悍的魅力,二十多年我的心魂只是在她划下的圈子里游荡。。
   我在想omg,我在哪里。。

posted @ 2008-06-02 00:06 闻太师 阅读(384) | 评论 (0)编辑 收藏

2008年5月26日

    我努力地想喊停,可时间不干。时间义无反顾地从我们之间流过,那些经不起考验的桥梁被冲垮,化作沉底的泥沙。面对这种摧枯拉朽的气势,我极其不适应。我心情复杂地回头望着逝去的一切,被时间推挤着被动前行。

posted @ 2008-05-26 11:38 闻太师 阅读(204) | 评论 (0)编辑 收藏

2008年5月18日

   代码:Tlist 出来的结果,发现有些函数没有显示,只在百度搜到一个相关帖子。那哥们在帖子中写道:
“我又试了几个类似的,貎似不能生成函数声明的tag,这也会影响到C-X C-O的补全效果。 通读了一遍ctags的document,搞定,看来以后还是应该少问多看。”
   之后竟无后话,bs之。尝试观摩ctags的manual,无奈E文残障人士,难解其意。
   尝试改变几次代码的格式,竟让我找到答案:ctags对#ifndef  #else #endif的结构解析有问题,会影响其后的函数解析,将其中的#else注释掉,update一下Tlist,重新生成一下标签文件即可满足阅读需要。
   再返过来看看ctags的manual,竟然找到对应的段子如下:

This implementation of ctags imposes no formatting requirements on C code as do legacy implementations. Older implementations of ctags tended to rely upon certain formatting assumptions in order to help it resolve coding dilemmas caused by preprocessor conditionals.

In general, ctags tries to be smart about conditional preprocessor directives. If a preprocessor conditional is encountered within a statement which defines a tag, ctags follows only the first branch of that conditional (except in the special case of "#if 0", in which case it follows only the last branch). The reason for this is that failing to pursue only one branch can result in ambiguous syntax, as in the following example:

#ifdef TWO_ALTERNATIVES
struct {
#else
union {
#endif

short a;
long b;

}

 

Both branches cannot be followed, or braces become unbalanced and ctags would be unable to make sense of the syntax.


   Sigh~How pool My English!

附 生成标签文件参数:
ctags -R --c++-kinds=+p --fields=+iaS --extra=+q src
在对C++文件进行补全时,OmniCppComplete插件需要在标签文件中包含C++的额外信息,因此上面的ctags命令不同于以前我们所使用的,它专门为C++语言生成一些额外的信息,上述选项的含义如下:
--c++-kinds=+p  : 为C++文件增加函数原型的标签
--fields=+iaS   : 在标签文件中加入继承信息(i)、类成员的访问控制信息(a)、以及函数的指纹(S)
--extra=+q      : 为标签增加类修饰符。注意,如果没有此选项,将不能对类成员补全

posted @ 2008-05-18 21:20 闻太师 阅读(3031) | 评论 (0)编辑 收藏

发信人: vale (浅谷), 信区: VIM
标  题: global命令详解
发信站: 水木社区 (Fri Jun 15 17:05:55 2007), 站内

global命令是Vim最强大的命令之一(个人认为是No.1),将其摸透用熟可以事半功倍,
本文总结了版上的一些经典问题,结合自己的使用和理解,试图通过实例详细介绍一下
其用法。示例难度不一,有些并没有多少实用性,为题而生,读者各取所需吧。示例说
明并不非常细致,以免罗唆。每节标题下列出了所涉及的内容在Vim help中的位置,以
供查找。文中用词未必标准(我没看过Vim中文帮助),观点也难免有错,请大家指正。

|1.| global命令形式
|2.| global与substitute
|3.| global标志的[range]用法
|4.| global与Vim脚本
|5.| 小结

==============================================================================
*1.* global命令形式

:h :g
:h 12.4

   :[range]global/{pattern}/{command}

global命令在[range]指定的文本范围内(缺省为整个文件)查找{pattern},然后对匹
配到的行执行命令{command},如果希望对没匹配上的行执行命令,则使用global!或
vglobal命令。

先来看Vim用户手册里的一个经典例子。

 【例1】倒序文件行(即unix下的tac命令)

   :g/^/m 0

这条命令用行首标记/^/匹配文件的所有行(这是查找的一个常用技巧,如果用/./则是
匹配非空行,不满足本例要求),然后用move命令依次将每行移到第一行(第0行的下一
行),从而实现了倒序功能。

global命令实际上是分成两步执行:首先扫描[range]指定范围内的所有行,给匹配{pa
ttern}的行打上标记;然后依次对打有标记的行执行{command}命令,如果被标记的行在
对之前匹配行的命令操作中被删除、移动或合并,则其标记自动消失,而不对该行执行
{command}命令。{command}可以是一个ex命令,也可以是用|分隔的多个ex命令,这样我
们就可以对被标记行,或从标记行寻址到的行进行多种不同的操作。

标记的概念很重要,现以例说明。

【例2】删除偶数行

    :g/^/+1 d

这条命令也是匹配所有行,然后隔行删除(其中+1用以定位于当前行的下一行)。为什
么是隔行呢?因为在对第一行执行+1 d命令时删除的是第二行,而第二行虽然也被标记
了,但已不存在了,因此不会执行删除第三行的命令。

本例也可以用normal命令实现:

    :%norm jdd

%指定整个文件,然后依次执行普通模式下的jdd,即下移删除一行。与global命令不同
之处在于,%norm是按照行号顺序执行,在第一行时删除了第二行,后面的所有行号都减
一,因此在第二行执行jdd时删除的是原来的第四行。也就是说,global命令是通过偶数
行标记的消失实现的,而normal命令是通过后续行的自动前移实现的。

【例3】删除奇数行

    :g/^/d|m.

光是:g/^/d显然不行,这会删除所有行,我们需要用move命令把偶数行的标记去掉。当
然,本例可以很简单的转换成【例2】,在此只是用来强调标记的概念。

本例若想用normal命令实现比较有意思,%norm dd也同样会删除整个文件,%norm jkdd
就可以,我不知道两者为什么不同,可能和normal命令内部的运行机制有关。

==============================================================================
*2.* global与substitute

:h 10.4
:helpg ms-word\c

不少vimmer觉得这两个命令差不多,的确,它们的形式很相似,都是要进行查找匹配,
只不过substitute执行的是替换而global执行的其它命令(当然,substitute缺省的[r
ange]是当前行,这点也不同)。先看两个例子,体会一下:s和:g不同的思维方式。

【例4】double所有行

   :%s/.*/&\r&/
   :g/^/t.

substitue是查找任意行,然后替换为两行夹回车;global是将每一行复制(:t就是:co
py)到自己下面,更加清晰明了。

【例5】把以回车排版、以空行分段的文本变成以回车分段的文本

很多txt格式的ebook,以及像vim help这样的文本,每行的字符数受限,段之间用空行
分隔。若把它们拷贝到word里,那些硬回车和空行就比较讨厌了,虽然word里也有自动
调整格式的功能,不过在Vim里搞定更是小菜一碟。先看看用替换如何实现。

    :%s/\n\n\@!/ /

\n\n\@!是查找后面不跟回车的回车(关于\@!的用法请:h /\@!,在此不多说了),然后
替换为空格,也就是去掉用于排版的回车。global命令则完全是另一种思路。

    :g/./,/^$/j

/./标记非空行,/^$/查找其后的空行,然后对二者之间的行进行合并操作。也许有人会
问,段中的每一行会不会都执行了j命令?前面已经说过,在之前操作中消失掉的标记行
不执行操作命令,在处理每段第一行时已经把段内的其余行都合并了,所以每段只会执
行一次j命令。这条命令使用global标记做为[range]的起始行,这样的用法后面还会详
述。

如果想要保留段落间的空行呢?若用替换实现,需要查找的是前后都没有回车的回车:

    :%s/\n\@<!\n\n\@!/ /

这样的正则表达式可能会令很多vimmer头大了。而对于global命令则只需要将合并范围
的结束位置上移一行就行了,由此可见global命令的方便之处。

    :g/./,/^$/-1j

global经常与substitute组合使用,用前者定位满足一定条件的行,用后者在这些行中
进行查找替换。如:

【例6】将aaa替换成bbb,除非该行中有ccc或者ddd

    :v/ccc\|ddd/s/aaa/bbb/g

【例7】将aaa替换成bbb,条件是该行中有ccc但不能有ddd

如何写出一个匹配aaa并满足行内有ccc但不能有ddd的正则表达式?我不知道。即便能写
出来,也必定极其复杂。用global命令则并不困难:

    :g/ccc/if getline('.') !~ 'ddd' | s/aaa/bbb/g

该命令首先标记匹配ccc的行,然后执行if命令(if也是ex命令!),getline函数取得
当前行,然后判断是否匹配ddd,如果不匹配(!~的求值为true)则执行替换。要掌握这
样的用法需要对ex命令、Vim函数和表达式有一定了解才行,实际上,这条命令已经是一
个快捷版的脚本了。可能有人会想,把g和v连起来用不就行了么,可惜global命令不支
持(恐怕也没法支持)嵌套。

==============================================================================
*3.* global标志的[range]用法

:h range

在global命令第一步中所设的标记,可以被用来为{command}命令设定各种形式的[rang
e]。在【例2】和【例5】中都已使用了这一技巧,灵活使用[range],是一项重要的基本
功。先看看【例2】和【例3】的一般化问题。

【例8】每n行中,删除前/后m行(例如,每10行删除前/后3行)

    :g/^/,+2 d | ,+6 m -1
    :g/^/,+6 m -1 | +1,+3 d

这两个命令还是利用move来清除保留行的标志,需要注意的是执行第二个命令时的当前
行是第一个命令寻址并执行后的位置。再看两个更实用点的例子。

【例9】提取条件编译内容。例如,在一个多平台的C程序里有大量的条件编译代码:

      #ifdef WIN32
         XXX1
         XXX2
      #endif
       ...
      #ifdef WIN32
         XXX3
         XXX4
      #else
         YYY1
         YYY2
      #endif

现在用global命令把Win32平台下代码提取出来,拷贝到文件末:

    :g/#ifdef WIN32/+1,/#else\|#endif/-1 t $

t命令的[range]是由逗号分隔,起始行是/#ifdef WIN32/标记行的下一行,结束行是一
个查找定位,是在起始行后面出现的#endif或#else的上一行,t将二者间的内容复制到
末尾。

【例10】提取上述C程序中的非Win32平台的代码(YYY部分)

首先说明一下,这个例子比前例要复杂的多,主要涉及的是[range]的操作,已经和
global命令没多少关系,大可不看。加到这的目的是把问题说完,供喜欢细抠的朋友参考。
本例的复杂性在于:首先,不能简单的用#else和#endif定位,因为代码中可能有其它的
条件编译,我们必须要将查找范围限定在#ifdef WIN32的block中;另外,在block中可
能并没有#else部分,这会给定位带来很大麻烦。解决方法是:

    :try | g/#ifdef WIN32//#else/+1, /#endif/-1 t $ | endtry

先不管try和endtry,只看中间的global部分:找到WIN32,再向后找到#else,将其下一
行作为[range]的起始行,然后从当前的光标(WIN32所在行,而非刚找到的#else的下一
行)向下找到#endif,将其上一行作为[range]的结束行,然后执行t命令。但对于没有
#else的block,如第一段代码,[range]的起始行是YYY1,而结束行是XXX2(因为查找
#endif时是从第一行开始的,而不是从YYY1开始),这是一个非法的[range],会引起
exception,如果不放在try里面global命令就会立刻停止。

与逗号(,)不同,如果[range]是用分号(;)分隔的,则会使得当前光标移至起始行,在查
找#endif时是从#else的下一行开始,就不会产生非法[range],用不着try,但带来的问
题是:没有#else的block会错误的把后面block中的#else部分找出来。

==============================================================================
*4.* global与Vim脚本

:h script
:h expression

经常有人问:XxEditor有个什么功能,Vim支持么?很可能不支持,因为Vim不大会为特
定用户群提供非一般化的功能,但很少有什么功能不能在Vim定制出来,如果是你常用,
就加到你的vimrc或者plugin里。脚本就是定制Vim的一种利器。本文不讨论脚本的编写,
而是介绍如何实用global实现类似脚本的功能,实际上,就是利用命令提供的机制,做
一个简化的脚本。

【例11】计算文件中数字列之和(或其它运算)

   :let i=0
   :g/^/let i+=str2nr(getline('.'))
   :echo i

首先定义变量i并清零,然后用str2nr函数把当前行转成数字累加到i中,注意Vim不支持
浮点数。global在这里实际上是替代了脚本里的for循环。

Vim中最常见的一个问题是如何产生一列递增数字,有很多解决办法,调用外部命令,录
宏,用substitute命令,还有专门的插件,而用global命令,可以实现一些更高级的功
能。见下例。

【例12】给有效代码行添加标号

在_Data Structures and Algorithm Analysis in C_一书中,作者为了便于讨论,将代
码中的有效行加上注释标号,例如:

   /*  1 */  unsigned int factorial( unsigned int n )
             {
   /*  2 */      if( n <= 1 )
   /*  3 */          return 1;
   /*  4 */      return( n * factorial(n-1) );
             }

为了在添加标号后能对齐,我们预先在每行代码前面插入足够多的空格(这当然很简单),
然后用global命令自动添加标号:

    :let i=1 | g/\a/s/ \{8}/\=printf("\/* %2d *\/",i)/ | let i+=1

其中变量i用来记录标号,g命令查找有字母的行,然后把前8个空格替换成注释标号,每
行处理完成后标号加一。替换中用到了/\=,一个非常有用的功能。

最后我们再回到删除特定行的例子,用变量来搞定。
【例13】每n行中,删除前/后m行

        :let n=10 | let m=3
        :let i=-1 | g/^/let i+=1 | if i%n<m | d
        :let i=-1 | g/^/let i+=1 | if i%n>(n-m-1) | d

我们用i来记录处理行的位置,通过i的值与m和n的关系决定何时进行删除操作,这样的处
理方式比【例8】的方法要清晰明了很多,而且更加通用。

==============================================================================
*5.* 小结

要用好global命令并非易事,命令中的每一部分都值得仔细研究:只有掌握了range原理
,才能自如的在文件中定位;只有精通pattern,才能有效的匹配到想要找的行;只有熟
悉ex命令,才能选用最合适的功能进行操作;只有对变量、表达式、函数等内容有一定
了解,才更能让global命令实现脚本的功能。总之,global是一个非常好的框架,对Vim
越是熟悉,就越能将其种种武器架设在其上使用,发挥更大的威力。

global当然并非万能,功能也有所欠缺,最主要的问题是只能用正则表达式来标志匹配
行,如果能用任意表达式来标记(或者从另一个角度,如前mv版主runsnake所说,引入
求值正则表达式),则可实现更加方便功能。比如前述的几个删除特定行的问题,将会
有简单而统一的解决方法。上述例子如果用sed、awk等专门的文本处理工具,或者perl
之类的script语言也非难事,有些实现起来会更加方便。本文提供的Vim解决方法未必简
单,甚至可能是难于理解,目的在于介绍global的使用。对于那些不会或者不能使用其
它工具的朋友,参考价值可能更大一些。其实Vim的功能实在很丰富,值得我们深入学习。
少林七十二绝技固然高妙,会的越多自然功力越强,不过只要会上一门六脉神剑或小无
相功,也足以独步江湖了。

==============================================================================
 vim:tw=78:fo=tcq2:isk=!-~,^*,^\|,^\":ts=8:ft=help:norl:

posted @ 2008-05-18 16:04 闻太师 阅读(463) | 评论 (0)编辑 收藏