VIM教程

VIM教程(3)2007-01-19 11:03                            各种 set 功能说明

autoindent(ai)
自动缩排,也就是说如果本行是从第五个字元开始写的,您按 Enter
后游标就会停在次行第五个字元处。预设是不打开的。

autowrite(aw)
档案一有更动就会自动存档。预设不打开。

background(bg)    <vim 才有>
可设成 dark 或 light,这是两种不同的 highlight 颜色设定,详见
$VIMRUNTIME/syntax/synload.vim。不过您要更动颜色的设定,最好
是设在 ~/.vimrc 或 ~/.gvimrc 中,原始档最好不要去动她。
     ㄟㄟㄟ,你从没提过 $VIMRUNTIME 好不好!其实这是最近版本的 vim 为了
       不至安装新版本时把旧版本的一些设定或 macro 档干掉,所以
       $VIMRUNTIME 就是 $VIM/vimxx,xx 就是版本号码啦!例如您使用的是 vim
       5.6 版,那么就是 $VIM/vim56。

backup(bk)
是否要 backup file。预设不打开。

writebackup(wb)    <vim 才有>
在写入档案前先备份一份,和 backup 的作用不尽相同,请
:h backup-table。预设是打开的,所以您如果不要 backup,那要关
掉的是这个项目,而不是 backup。但请先检查一下您编译时是不是
有编译进去,请 :ver。

backupdir(bdir)    <vim 才有>
设定存放 backup file 的目录。预设在所编辑的档案之所在目录。

binary(bin)    <vim 才有>
设在编辑二进位档状态,这是防止存二进位档时把 EOL 也写进二进位
档,那就会悔不当初,如果是图档将会无法再观看,如果是可执行档就
无法执行了!因此预设是 off。
    
elvis 会自动判断是否为二进位档,而且会分成左右两半,左半部会以 16
       进位的方式显示,右半部则是以 ASCII 的方式来显示。

browsedir(bsdir)    <vim 才有>
浏览档案的目录,GUI 版本始有。预设是上一次浏览的目录。就是 GUI
版本功能表上的 [File] -> [Open] 会打开的目录。

cindent(cin)    <vim 才有>
写 C 时很好用,indent 比一般敏感,专为 C 程式码而设。预设 off。
编辑 C/C++ code 时会自动打开。

cmdheight(ch)    <vim 才有>
状态列的行数,预设一行,建议设成两行。

compatible(cp)    <vim 才有>
设为和原始 vi 相容的状态,vim 的扩充功能会被抑制。预设 off。

confirm(cf)    <vim 才有>
各种确认动作。预设 off。

directory(dir)
swap 档存放的目录。前面单元已有说明。

fileformat(ff)   <vim 才有>
这是写入档案时置放 EOL(end of line) 的形式
dos 是以 0D 0A 来断行。
unix 是以 0A 来断行。
mac 是以 0D 来断行。
预设以各系统平台而定,在 Linux 当然是 unix 形式。

fileformats(ffs)    <vim 才有>
可指定多个,会依载入的档案形式来调整 ff。
例如 :set ffs=unix,dos ff=unix
则预设为 unix 格式,但如读入的是 dos 格式的档案,会自动调整
为 dos 格式,这样存档时就会以 dos 格式存档(状态列会显示)。
。此时如要改成 unix 格式,可 set ff=unix 然后存档就会转成
unix 格式,反之亦然。
     如果不这样设,也就是您不管 ff 或 ffs 都设成 unix,那读入 dos 格式
       的档案时在每行尾会出现 ^M 这个字元(就是 0D 啦!)这时纵使 :set
       ff=unix 也来不及了!只好 :%s/^M//g 来消去这个 ^M。ㄟ,还记得怎么替
       换吗?就是把 ^M 换成没有啦!而且 ^M 怎么打出来的还记得吧!翻一翻前
       面的单元吧!
    
Hey,你怎么知道是 0D 呀!好吧!告诉您一个密秘,您把游标移到 ^M 那
       个位置,然后按 ga 在状态列就会显示 10,16,8 进位的值。其它的字元
       也是可以如此显示。a 就是 ascii 的意思。但这是 vim 的扩充功能
       ,elvis 没有。
     elvis 纵使载入 dos 格式的档案,也是会自动把 ^M 隐藏起来。

ignorecase(ic)
寻找时不分大小写,这对中文会造成困扰。预设 off。

incsearch(is)    <vim 才有>
加强式寻找功能,在键入 patern 时会立即反应移动至目前键入之
patern 上。预设 off。

hlsearch(hls)    <vim 才有>
寻找时,符合字串会反白表示。预设 off。如果您是使用 vim 的
预设的 vimrc 档的话,会设在 F8 键来切换。

textwidth(tw)
是一种 word wrap 的功能,从左起算之固定每行的最大字元宽度。
超过此宽度就会自动折行,这可是真的折行,也就是说在折行处会插
入 EOL。预设是 0,也就是没有 word wrap 的功能。

wrapmargin(wm)
和 textwidth 作用相同,只是是从右视窗边向左算起要几个字元起
折行。预设是 0。textwidth 与 wrapmargin 的功能目前并不适用於
中文,打中文还是您自行按 Enter 吧!

wrap
这也是折行功能,可是只是萤幕效果的折行,实际上并没有插入 EOL。

wrapscan(ws)
这和折行没有关系,是指寻找时,找至档尾时,是否要从档首继续找。
预设是要。

paste    <vim 才有>
这是防止在做剪贴时位置会不正确,前面单元已有说明。

ruler(ru)    <vim 才有>
会在状态列显示游标所在处之行列状态,预设不打开,但建议打开。
最右边之代号的意义如下:
Top 档案第一行在萤幕可见范围。
Bot 档案最后一行在萤幕可见范围。
All 档案首尾皆在一个萤幕范围内。
如非以上三种情形,则会显示相对百分比位置。

statusline(stl)    <vim 才有>
状态列显示的格式,使用预设就可以了,如果您想骚包一下的话,那
就请您 :h stl。

shiftwidth(sw)
指由 >> 移动整行内容时,一次移动的字元宽度,一般是使用 Tab 的
值,但可由这个设定来改变。

tabstop(ts)
一个 Tab 键宽度。预设是 8 个字元宽度。最好不要随便改,以免您写
的东西由其它编辑器来阅读时造成困扰,为解决这个问题,vim 有一种
softtabstop 的机制,在下一节会详细说明。

showcmd(sc)
在状态列显示目前所执行的指令。

showmode(smd)
在状态列显示目前的模式,例如是 Insert mode 或是 Visual mode。
当然平常的 normal mode(commond mode)是不显示的。

viusalbell(vb)    <vim 才有>
以萤幕闪动代替 beep 声。

number(nu)
显示行号。注意,冒号命令也有 :nu 这是显示游标所在行的行号,您
嫌多打一个字的话,:# 也行。不过如果 ruler 打开的话,在状态列本
就会显示门前游标所在处的行列值。

list
这也可以算是一种模式,list mode。就是 Tab 的地方会以 ^I 显示,
而行尾之 EOL 会显示成 $。可以让您清楚的知道 Tab 在哪里,折行是
不是真的。

swapfile(swf)    <vim 才有>
是否需 swap 至磁碟。如果设为 noswf 的话,那将不会有 swapfile
产生,通通会载入在记忆体中。预设是要 swapfile。

fileencoding(fe)    <vim 才有>
首先先鼓掌一下,啪啪啪…,因为有支援 taiwan,也支援 XIM,也
就是说可以使用 xcin-2.5x 来作输入,当然您用 xcin-2.3x 配合
XA 也是可以啦!目前支援简繁中文、日文、韩文,unicode 尚未植
入。但前提是您要把 multibyte 编译进去,这在一开始就讲过了。
预设是使用 ansi。set guifont 及 set guifontset 已在一开始讲
过,在此就不重复了。

history(hi)
记录冒号命令的历史纪录档,就是可以用上下方向键叫出来的那锅。
预设是 20 笔。


                           关於 softtabstop(sts)

   几乎所有的 OS 及软体都设定 Tab 就是 8 个字元长,这已经是个公认值,您硬
   要去改变它的话恐怕带来许多不便,但实际上关於程式风格,许多人又认为 8
   个字元太长了,几个巢状回圈下来就需折行,反而不方便。因此 vim 体贴您,
   内建了 softtabstop 的功能,就是由 vim 来代您制造出一个假的 Tab,实际上
   是空白字元组成的 Tab。

   举个例子来说明比较清楚。
set softtabstop=4
set shiftwidth=4

   这样会由 4 个空白字元取代一个 Tab,您按 Tab 键 vim 就跳 4 格,需注意的
   是,如果您按了三次 Tab 键,那就是一个实际的 Tab 加上四个空白字元,可不
   是 12 个空白字元喔!是混合 Tab 及 space 的。

   问题来了!那我要按真正的 8 字元的 Tab 时怎么办?简单,还记得怎么按特殊
   字元吗? Ctrl-v Tab 或 Ctrl-v I 就可以了,那就是如假包换的 8 字元长之
   Tab。当然,您按两次 Tab 不就得了!:-)


                                  关於折行

   前面已说过 set wrap 就可以造成萤幕折行,可是却会把一个英文单字折成两半
   ,实在很不雅观。好了,vim 再体贴您一次,set linebreak(lbr) 就会避免这
   种问题发生,会在空白或标点符号的地方来折行,但也仍属萤幕折行,并不会插
   入 EOL。这个功能目前在中文判断上还是会出槌!:-(

   [4]前单元 [5]次单元 [6]目 录

     __


   最后修订日期:2000.04.06
   [7]Edward Lee




   [1]前单元 [2]目 录

                  大家来学VIM(一个历久弥新的编辑器)[十]

                              规则表示式的运用


      在本系列文章一开始就说明了学 vi(m) 可以顺便学规则表示式(regular
   expression,以下简称 regexp),那为什么到现在才来讲呢?因为 regexp 说
      简单也算不很难,但您要深入去使用的话,有时会马上看不出一个复杂的
   regexp 在说些什么的,就曾有人形容 regexp 为「有字天书」!而且在 vi(m)
    整体都还没一个概念就加入 regexp 的话,那后面的单元恐怕就没人看了!而
   regexp 各家有各家的 extensions,这也是大家视为畏途的原因之一,不过总是
   大同小异,只需注意一下就可以了。目前先不必管别家怎么说,就让 vim 暂时
   先成为我们的「标准」,以后碰到其它程式的 regexp 应该就可以触类旁通。以
   下我们尽量由实例去了解。当然,小小的一篇文章是没有办法详尽介绍,只能捡
   重点来说明了。如有疑问,可 :h pattern 或在 Un
x 系统中可 man 7 regex,
     甚至 man ed,man sed,man grep,man awk,man perlre 里面也是会说些
   regexp,但要注意和 vim 差异的地方!其中 perl 的 regexp 应该是最完整的
   了,如果您的系统没有 perl 那应该是「稀有动物」了!:-) ㄟㄟㄟ!vim 只是
                     一个编辑器,可不是独立的程式语言!


                                 基本的匹配

指前所绑住的字元或字元集合,出现 0 次或 0 次以上。
+ 和
作用相同,但不包括出现 0 次。
= 指前所绑住的字元恰好出现 0 或 1 次。
| 这是多选,就是 or 的意思,被 | 隔开的 pattern,任一个符
   合的话就算符合。
     +, =, | 会加上一个 ,是因原字元在 vi(m) 就具有特殊意义,在一般
       的 regexp 中是 +,?,| 就可以了,只是提醒您一下,以免搞混了!
    
记住  + 是不可数的!用辞不是是精确,只是帮助您记忆啦!
    
在 elvis 及 ed 中是使用 ? 来匹配出现 0 或 1 次,而不是 =,这里要
       非常小心!

   [实例] dg
   指
前所绑住的字元 g 出现 0 次或 0 次以上。也就是说 d(出现 0 次),dg
   ,dgggg,dgggggggg 都是符合这个 pattern。如果您下寻找指令 /dg,那符合
   这个 pattern 的字串都会被找出来。如果用在代换就要非常小心了,像
   extended 中的 d 也是会被置换掉的。例如您下 :%s/dg
/test/g 的话,那
   extended 这个字会换成 extentestetest。

     shell 中使用的通用字元为 pattern matching notation 和 regexp 不同
       的。dg
在 shell 中是解为以 dg 开头的任意字串,这就不包括 d 在内了
       ,也就是说在 shell 中, 是代表任一字元或字串。

   [实例] dg+
   dg, dgg, dgggggg 皆符合,但 d 则不符合。如果是 dg= 的话,就只有 d、dg
   这两个符合了。

   [实例] :%s/The|All/test/g
   全文中只要是 The 或 All 都会被替换成 test。注意,如果文中有 There 也是
   会被替换成 testre!要如何避免这种情形呢?下面会另述及限定使用法。

   [实例] /123-=4567
   这样会找出,123-4567 及 1234567。当然 123-456789 也是会被找出来。

[…] 字元集合,表示中括号中所有字元中的其中一个。
[^..] 这是上述 […] 的补集,表非中括号内字元的其中一个。
.      除换行字元外的任一单一字元。指本身,非指前所绑之字元。
       就好像 shell 中的 ? 一样。如果要指定真正的英文句点,要
       用 来 escape,就是说 . 这时的 . 是代表真正句点,而不
       是 regexp 中的特殊意义。其他如
亦同。

   [实例]

   [Aa]
          A 或 a 其中的一个。

   [12345]
          12345 其中的一个数目字。可用 [1-5] 来表示。连续性的数目字或字元
          可用 - 来隔开,写出头尾来代表就可以了。[0-9] 就表 0 到 9 的数目
          字,[a-d] 就代表 abcd 四个英文字母

   [实例] W[0-9].cc
   这个例子是说以 W 开头,后接 0-9 其中一个或多个数目字或不接什么,然后是
   一个句点,最后是 cc。所以 W.cc,W1.cc,W2.cc,W345.cc,W8976543287.cc
   皆符合。如果要表示 W 及 .cc 间夹一个以上的数目字,要写成
   W[0-9][0-9]
.cc。

   [实例] .
   这代表任意字元或字串,或什么都没有,脑筋急转弯,对照前面的定义想一下。
   当然这是不包括换行字元的。

   [实例]
   [^M] 表除 M 以外的任意字元。
   [^Tt] 表 T 及 t 以外的任意字元。
   [^0-9] 表非数目字之字元。
   [^a-zA-Z] 表非英文字母之字元。

    
注意,^ 要在中括号内,且在最开头的地方,否则另有含意。

^ 匹配行首,指其后绑住的字串,出现在行首才符合。
$ 匹配行尾,指其前绑住的字串,出现在行尾才符合。含换行字元。
     不是在行首的 ^ 指的是 ^ 这个字元。不是在行尾的 $ 是指 $ 本身这个字
       元。

   [实例] /^What
   这样只有在行首的 What 才会被找出来。注意! Whatever, What’s 也是会被找
   出来。如果是 /What$ 则是在行尾的 What 才会被找出来。

   [实例] ^$
   这是什么东东?行首也是行尾的行。ㄚ,就是空白行嘛!当然也不能说这个行是
   没有什么东东啦!空白行至少也是会有个换行字元。在后面会详述如何消除全文
   的空白行。

(…) 记忆 pattern,可由 1, 2…9 来叫出。

   [实例] :%s/([a-z])1/test/g
   这样 aa, bb, cc, dd, …, zz 都会被 test 替换掉。这和
   :%s/[a-z][a-z]/test/g 是不一样的意思,后者会把 aa, ab, ac… ba, bb,
   bc…zz 都换成 test。也就是说 (…) 由 1 叫出时会有对称性的配对出现
   。

   [实例] :%s/(.)(.)r21/test/g
   会将中间为 r,前有二个任一字元,后有两个具对称性的字元所组成的字串替换
   成 test。2 是呼叫第二组 (.),而 1 是呼叫第一组 (.)。例如:12r21
   ,cfrfc,7grg7 等都会被替换成 test。

< 匹配字(word)首。所谓 word 包括文数字及底线。
> 匹配字尾。这就是前所提及的限定用法,被 <,或 > 括住的
    pattern 就会被限制住,使 regexp 不能再向右(左)扩充解释。
    
ed 及 perl 中可以 b 来表示这两个符号,perl 中只支援 b,ed 则 b
       及 <, >皆支援。但在 perl 可多加个 ? 来限制 regexp 的扩充解译。
     功能上而言,这是和 ^ $ 一样的定位样式(anchor pattern)指所绑住的
       字串必须是单字边界(word boundary),前或后或前后除了空白字元及标
       点符号外不可再有其它字元。
    
在 vim 中 b 是表示 <BS> 即 backspace 键。

   [实例] :%s/<abbbc>/test/g
   这样只有 abbbc 才会被替换成 test。如果没有这样限定,:%s/abbbc/test/g,
   那 deabbbcly 中的 "abbbc" 亦会被替换成 test。所以前面
   :%s/The|All/test/g 可换成 :%s/<The>|<All>/test/g 这样一来,There
   就不会被替换成 testre 了!

   [实例] :%s/<abbbc/test/g
   这样的话,只要是以 abbbc 为首的字(word),其中的 abbbc 的部份都会被
   test 所替换。注意!是指字首,而不是指行首。所以 abbbc,abbbcerd
   ,abbbckijuds 都符合。

{n,m} 指前所绑住的字元或字元集合最少出现 n 次,最多出现 m 次。
     这在一般的 regexp 表示成 {n,m}。vim 及 elvis 两种表示法皆支援
       。perl 则直接使用 {}。以下会举四种不同的例子,请大家发挥一下想像力
       。:-)

   [实例] {最小值,最大值}
   如 [0-9]{3,4} 匹配至少三位数,但不可多於四位数的数目字。如:
123
12
1
123456
1234567
12345678
1234
12345

   如果下 :%s/[0-9]{3,4}/test/g 的话,那 1,12 这两组不会被替换,因为不
   满 3 位数。而 12345,则会换成 test5。123456,则会换成 test56。12345678
   ,则会换成 testtest。1234567 也是会换成 testtest。123,1234 这两组则会
   被替换成 test。您可以亲自操作一次就知道怎么一回事了。操作时最后加 gc
   来 confirm,这样您会更了解实际替换的内容。ㄟ,别忘了 u 可以回复您的编
   辑动作。

   [实例] {数目字}
   xy{20} 表示 x 后接 20 个 y。
   e[x-z]{4} 表示 e 后接有四个字元,是 x,y,z 的其中一个的
         组合。如:exxxx, exyyz, ezzyz, exyzz 皆符合。

   [实例] {最小值,}
   xy{2,} 表 x 后接至少二个的 y。相当於 xyyy
或 xyy+ 。

   [实例] {,最大值}
   xy{,4} 表 x 后接至多四个或更少的 y (可能没有)。
        因此 x, xy, xyy ,xyyy, xyyyy 皆符合。


              中介字元(metacharacter, or character classes)

   主要是简化 regexp 的书写。
s 表空白字元,即 <Space> 或 <Tab>。
     不含换行字元,这是编辑器的特性使然。在 perl 的 s 是包含换行字元的
       。而且 vim 及 elvis 皆不支援 n 这种换行中介字元。

S 表非空白字元。
d 表数目字(digits),即 [0-9]。
D 表非数目字,即 [^0-9]。
w 表一般字元(word character),包括底线。即 [0-9a-zA-Z]。
W 表非一般字元,即 [^0-9a-zA-Z
]。
a 表英文字母(alphabetic character),即 [a-zA-Z]。
A 表非英文字母,即 [^a-zA-Z]。
l 表小写字母(lowercase character),即 [a-z]。
L 表非小写字母,即 [^a-z]。
u 表大写字母(uppercase),即 [A-Z]。
U 表非大写字母,即 [^A-Z]。
    
原始 vi 不支援此种中介字元。
     使用中介字元的比对速度将会比使用字元集合 [] 的快。


                                全域性的指令

:[range]g/pattern/[cmd]

   cmd 是 ed 可用的指令,预设是 p(print),您可查一下 man ed,就可以知道有
   什么指令可用。这个小节里主要是说明 d(delete) 的功能。因为是要说明如何
   消除空白行。需注意的是,d 是行删除指令,凡含 pattern 的整行都会被删掉
   ,而且 range 不指定的话,预设是全篇文章,因为 g 就是代表 globe。
    
在 vim 的 help 档里说的是 ex 指令,但 ex 实际上是和 vim 连结的,因
       此这里特别指出 ed。但 ed 的指令少数可能会和 vim 的 ex 不同,这是因
       为 ed 和 vim 并非同步在发展,作者也非同一人。

:g/^$/d

   这样就会删除全文的空白行。前面已提过 ^$ 代表的是空白行。但这里有个问题
   ,如果空白行里包含了其它空白字元(即 Space 或 Tab)的话。表面看起来是
   和一般空白行一模一样,但却暗藏玄机,用上面的方法就无法删除这种空白行了
   !怎么办?来!看招!
:g/^[<Space><Tab>]$/d

   在 vim 或 elvis 里您可以如此照打,也就是 <Space> 代表空白字元,<Tab>
   代表按 Tab 键的结果。在原始 vi 则不行,得自行按出特殊字元出来,就是
   Ctrl-v Space 及 Ctrl-v Tab。或采更简单的打法:
:g/^s
$/d

   还记得中介中元吗?好用吧!少打了不少字。:-) 意思就是删除含 0 或 1 个以
   上空白字元的行。

   有些书中写成 :%s/^$//g 可以删除空白行,这是错误的,因为 :s 这 个指令只
   更动一行里的内容物,但不会做删除一行的动作。


                                 & 替代变数

   代表置换时合於 patern 的字元或字串。

   [实例] :%s/uddddddddd>/ID:&/g
   这样全文中的身份证字号前就会加上 ID: 字样,也就是说 T123456789 会被换
   成 ID:T123456789。还记得吗? d 就是 [0-9],u 代表大写的英文字母。加
   个 > 是防止 T12345678999 也被换掉。当然前面再加个 < 更保险。ID: 字样
   您用中文也行!
   另一个好用的例子是电话号码前加上 TeL:,就请您自行练习了!

   [实例] 将档案 3 至 7 行的资料向右移 2 个空白
:3,7s/./ &/

   但这样连空白行也是会插入空白字元,较高明的做法是:
:3,7s/.+/ &/

   这样空白行就不会去动它了!想通了 .
及 .+ 的意思了吗?往前翻一下 .
   + 的定义。

   [实例] 将档案 3 至 7 行的资料向左移 2 个空白
:3,7s/^ //

   就是删去行首的二个空白啦!

   [实例] 将全文的 Edward 这个单字,前后加上中括号
:%s/<Edward>/[&]/g

   [实例] 将全文的 Edward 这个单字,改成大写的。
:%s/<Edward>/U&/g

    
ㄟ!U 不是代表非大写字母吗?喔!您搞错位置了。U 在 pattern 的位
       置的时候是指非大写字母的样式,即 [^A-Z],但如果是在置换字串位置的
       时候是指将其后的字串通通改成大写。与其相对的是 L,会将其后的字串
       改为小写。详细请 :h sub-replace-special。

   [实例] 将全文每行最后加上 <BR> 这个 HTML tag。
:%s/./&<BR>/g

   怎么样,是否已感觉到 regexp 威力无穷了呢?还是您已经快睡著了呢?:-) 不
   过也请您想想,如果是在没有 regexp 功能的编辑器里,范例中的一些动作您会
   怎么做呢?一个一个去改?


                                greedy 陷阱

   regexp 会有贪心的倾向,什么意思呢?就是说在同一行内,如果有多个符合
   pattern 的情形,会找最长的那一个。
    
注意!greedy 的特性是针对会反覆比对的 regexp 而言,例如:, =,
       +, {} 等。前面所举的 .
的例子,由於 greedy 的关系,在整篇文章中
       做替换时,会被当成是每一行整行,因为 regexp 会去找每一行最长符合的
       那一个。

   [实例] This is a test. Test for regexp.
   如果您下 :%s/[Tt].*t/program/g 原意是想把所有的 Test 或 test 换成
   program 的,结果由於 regexp 的贪心,整个 "This is a test. Test" 会换成
   program。结果原文就变成了 program for regexp. 因此在全文替换时要非常小
   心,避免使用弹性太大的 regexp。像此例,只要下
   :%s/<[Tt]est>/program/g 就可以了!


   最后提醒您,这可不是 regexp 的全部,碍於篇幅及在下功力的问题,当然是没
   办法全面详尽的向各位做介绍,在下只是将各位领进门,修行就得看各位了!如
   果还想更深入的研究 regexp,可参考: Mastering Regular
   Expressions(O’Reilly & Associates) 一书。

   [3]前单元 [4]目 录