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 或在 Unx 系统中可 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]目 录