Vim编辑器强大的搜索引擎可以使得我们快速的执行各种类型的查找,从而大的方便了我们的编辑工作,使得我们的编辑工作更加快速和高效.
我们在进行查找的过程中可以打开高亮显示选项,这样在我们找到我们想要的字符后,Vim就会将字符串进行高亮显示,我们也可以很方便的知道我们要找的字符串在哪里.我们可以使用下面的命令来打开高亮显示选项:
:set hlsearch
关闭这个选项的命令为:
:set nohlsearch
在默认的情况下Vim编辑器是很敏感的,也就是Vim编辑器可以很好的来区分一个单词的大小写,从而可以准确的查找得到我们想要的字符串.例如如果一个文件中有这样的几个字符串:
include,INCLUDE,Include.当我们使用命令/include来查找字符串时只有include字符会被高亮显示.
但是如果我们打开ignorecase选项后再执行这个命令结果就不一了,这时所有的类似的字符都会被高亮显示.打开这个选项的命令为:
:set ignorecase
但是这样的查找结果并不是我们想要的,也不是我们所希望发生的,因而我们常用下面的命令选项设置:
:set noignorecase
这样Vim就可以正确的查找我们想要的字符串.
如果我们设置了ignorecase选项后,我们想要查找字符串word,而匹配的则可能是word,Word,WORD.如果我们要查找字符串WORD,匹配的结里也是一样的.但是如果我们设置了以下的两项后的执行结果就会变得不一样了:
;set ignorecase
:set smartcase
经过这样的设置以后,如果我们输入的是小写字符,那么Vim就会匹配各种可能的组合,这时与设置了ignorecase的情况相同,但是如果我们在输入中有一个大写字符,那么这时的查找就变成了精确查找了,与设置了noignorecase的情况相同.
在默认的情下,我们输入要查找的字符串,vim是从当前光标处向前查找,直到文件的结尾,如果没有打到,那么就会从文件的开头开始查找,直到光标所处的位置.我们可以通过设置选项nowrapscan来禁止这种循环查找的方式,这个命令如下:
:set nowrapscan
这样以后如果已经查找到文件的底部时就会在Vim底部显示出一条错误信息.如果我们想要回到正常的状态,我们可以使用下面的命令;
:set wrapscan
如果我们正处在一个很长的查找过短中而我们想要停止这一查找开始我们新的工作,这时我们可以使用CTRL-C命令,如果是在Windows系统上则要使用CTRL-BREAK命令.
我们在编辑文件的过程中还可以使用立时查找的命令.如果我们想快速查找当前光标下的字符串,我们可以使用命令*,这个命令可以向前查找与当前光标下的单词精确匹配的字符串.而命令#则向前查找与当前光标下的字符精确匹配的字符串.换句话说如果当前光标下的字符串为word,在执行*命令查找时并不会与Word相匹配.与这个立时查找命令相类似的就是g*命令.这也是一个立时查找的命令,只不过他不会进行严格的整字匹配,如果用这个命令来查找word那么就有可能和Word相匹配.而g#命令与其相同,只不过他是向相反的方向进行查找匹配.
在默认的情况下,在查找时Vim会将光标放在第一个匹配的结果的开始处.我们也可以指定查找结束后光标所处的位置.对于向前查找的命令我们可以斜线后用数字来指明光标所处的位置,如下面的命令:
/set/2
这个命令会在查找结束后将光标入在第一个set字符串后第二行的开始处.
在这个命令中这个数字可以是正数也可以是负数.如果仅是一个简单的数字,光标会被放在第一个匹配字符串处后或是前的数字所指定的行的开始处.正是向后,负数是向前.如果斜线后是b和数字的,那么在查找结束后,光标将会被置于第一个匹配字符串的开始处,然后向左或是右移动n个字符,这里的n即为数字所指定的数.如果为正数则是向右移动,如果是负数,则是向左移动.如下面的命令:
/set/b2
这个命令会使用Vim在查找结束后将光标放在第一个匹配字符的开始处,然后向右移动两个字符,也就是说最后光标会位于第一个匹配字符串中的t的位置.将b改为s也是一样的效果.
与参数b或是s相类似是e参数,这个参数会使得光标放在第一个匹配字符串的结尾处.同样我们也可以指定数来指是向右还是向左移动光标以及移动的字符数.如下面的命令:
/set/e
这个命令会使光标放在第一个匹配字符处的结尾处,在没有指定数字时是这个样子的.而下面命令:
/set/e2
这个命令是会将光标放在第一个匹配字符串的结尾处,然后向右移动2个字符.这里的数字如果是正数则向右移,如果为负数,则向左移.
例如下面的命令:
/set/e+2
这个命令是告诉Vim在查找set字符串结束后将光标放在第一个匹配字符串的结尾处,然后向右移动两个字符.在这里我们将这个数字称为偏移量.如果我们要重复上一次的查找但是需要不同的偏移量我们可以用下面的命令:
//5
不使用偏移量时我们可以指明一个空的偏移量,如:
//
例如下面的一些例子:
/set/e+2
向前搜索字符串2,并将光标放在第一个匹配字符串的结尾处,然后向右移动2个字符
/ 重复前一次的查找,使用相同的偏移量.
// 重复前一次的查找,但是不使用偏移量.
我们还可以使用查找命令?来进行类似的查找,例如:
?set?b5
这个命令是告诉Vimu将光标放在最后一个匹配字符串的开头部分,然后向右移动5个字符
??-2命令则继续前一次的查找命令,但是使用新的偏移量.
??命令是继续前一次的查找命令,但是不使用偏移量.
但是有一件事我们要清楚的就是我们在用偏移量进行光标定位时的查找是从当前光标所在处开始的,这会给我们带来一些麻烦.例如我们在执行命令/set/-2时Vim会将光标放在第一匹配的字符串处,然后上移两行.当我们用n命令来重复上一次的查找时,我们会找到我们刚才找到过的那个字符串,然后再向上偏移两行.这个结果就是不论我们输入了多少的次n命令,我们仍是在原地踏步的,哪里也去不了.
Vim使用通用的表达式(regular expressions)来进行逻辑查找.我们在以前讨论过用简单的字符串进行查找,但是这里我们将要看到的通用字符串查找要简单字符查找的功能强大得多.通过在我们的命令中使用通用表达式,我们可以查找任何一种字符类型,例如我们可以查找以t开头而以ing结尾的字尾串(通用表达式为\<t[^]*ing\>).然而这种强大的功能也是要付出一定的代价的.通用表达式是神秘的和简洁的.也许我们要花上很上的一段时间才会习惯这种查找方式,然后才能掌握这个强大的查找工具.
在学习这些通用表达式的查找的过程中我们最好将高亮显示这个选项打开,这样就可以使Vim高亮显示最后一次查找的匹配结果.打开高亮显示的命令为:
:set hlsearch
一个通用表达式是由一些元素组成的.这些元素是通用表达式中最小的匹配单位.一个元素可以是一个字符,例如a,与字符a相匹配,或者是一个特殊字符,例如$,匹配一行的结束.还可以是其他的字符,例如\<,是指一个单词的开始.
在通用表达式中,我们用\<来匹配一个单词的开始,用\>来匹配一个单词的结束.也就是说要将我们想要查找的字符串放在这两个中间.这样我们就可以精确的来查找我们想要查找的字符串,而不会有其他的一些匹配情况.而如果我们用简单字符串形式来查找,我们就会得到许多的匹配情况,甚至在一个单词中的组成部分也可以成为匹配情况.例如在文件中有Californian,Unfortunately.如果用命令/for来查找,那么就会找到这两个单词.而如果我们用通用表达式\<for\>来进行查找,则只会精确的查找到for,而不会用其他的匹配情况.这时的命令形式如下:
/\<for\>
我们在进行查找的时候还可以使用一些修饰符来进行表达式的组合.例如修饰符*就可以表示一个字符可以匹配0次或是多次.换句话说,Vim编辑器会进行尽可能多的匹配.所以通用表达式te*可以匹配te,tee,teee等等.基于还可以匹配t,为什么呢?因为在这里e可以匹配0次,所以就可以匹配t.而修饰符\+则表明这个字符可以匹配一次或是多次.所以表达式te\+可以匹配te,tee,teee等等.但是这一次这个表达式不可以再匹配t了,因为这里e最少要匹配一次.
最后一个修饰符\=表示一个字符匹配0次或是一次.这就是说表达te\=可以匹配t,te,但是不可以是tee,虽然这个命令会匹配tee的前两个字符.
还有一些特殊的字符可以来匹配一定范围的字符.如\a匹配一个字符,而\d匹配任何数字.所以表达式\a\a\a可以匹配任意三个字符.例如下面的命令可以查找任意四个数字:
/\d\d\d\d
我们还可以用下面的命令来查找任意后带一个下划线的三个字符:
/\a\a\a_
\a可以匹配所有的字符(小写的或是大写的).但是假如我们现在只要匹配元音字符又该如何来做呢?这时我们可以使用范围作用符[].范围作用符可以匹配一系字符中的一个.例如[aeiou]只匹配一个小写元音字符.所以表达式t[aeiou]n可以匹配tan,ten,tin,ton,tun.
我们还可以通过短横线来在括号内指明字符的范围.例如[0-9]可以匹配0到9中的任一字符.
我们还可以组合其他的字符.例如[0-9aeiou]可以匹配任意一个数字或是小写的元音字符.
而修饰符^可以指代除本身以外的所有字符.
下面列出一些匹配的情况:
表达式 匹配结果
one[\-]way one-way
2\^4 2^4
2[\^*]4 2^4,2*4
如果我们要指找所有的大写字符又应如何来做呢?一个办法就是使用表达式[A-Z].还有一个办法就是我们可以使用预先定义的字符类.[:upper:]可以匹配大写字符.所以我们要指找大写字符也可以这样的来写:[[:upper:]].我们可以使用字符类来写出所有的字符:
[[:upper:][:lower:]].
在Vim中还有许多不同的字符类定义
我们还可以通过表达来指出一个字符重复的次数.这个的一般格式如下:
\{minimum,maximum}
例如表达式a\{3,5}可以匹配3到5个a.在默认的情况下Vim将会尽可能多的进行匹配.所以表达a\{3,5}最多可以匹配到5个a.
在这个命令格式中最小次数可以省略,Vim默认的情况下最小次数为0.所以表达式a\{,5}可以匹配0到5个a.最大次数也可以省略,在这种情况下Vim默认匹配无穷大.所以表达式a\{3,}最少可以匹配3个a,最多是尽可能的多.
如果我们只指定一个数字,那么Vim就会精确的匹配相应的次数.例如a\{5}只会精确的匹配5次.
如果我们在数字前加了一个负号(-),那么Vim在查找时就会尽可能少的进行匹配.
例如a\{-3,5}匹配3到5个a,但是会尽可能少的进行匹配.事实上这个表达式仅会匹配3个a,哪怕是我们的文件中用aaaaa,Vim也只会尽可能少的进行匹配.
表达式a\{-3,}匹配三个或是更多个a,并且尽可以少地的进行匹配.而表达式a\{-,5}可以匹配0到五个字符.表达式a\{-}可以匹配0到无穷大个字符.在通常情况下这个表达式匹配0个符,除非在他的后面还有字符或是表达式.例如[a-z]\{-}x将会匹配.cxcx中的cx.而表达式[a-z]*x将会匹配整个cxcx.最后表达式a\{-5}将会精确的匹配5个字符.
我们还可以使用运算符\(和\)定义一个组.例如表达式a*b可以匹配b,ab,aab,aaab等等.而表达式a\(XY\)*b可以匹配ab,aXYb,aXYXYb,aXYXYXYb等等.
我们还可以用或运算运符\|来查找两个或是多个可能的匹配.例如通用表达式foo\|bar可以查找foo或是bar.
现在我们知道了这样多的表达式的表示方法,那么我们如何来应用他们呢?例如我们现在要查的内容为1MGU103.这个字符串是由1个数字,3个大写字符,3个数字组成的.可以有几种方法来表示:
一是先表示前面的一个数字:[0-9],然后加入大写字符后就成为了:[0-9][A-Z].因为有三个大写字符我们可以加入精确匹配的数字:[0-9][A-Z]\{3}.最后我们再加入最后面的三个数字.所以最后的结果就成了:[0-9][A-Z]\{3}[0-9]\{3}
另一种利用\d指任何的数字,而\u指任何的大写字符.所以用这样的方法写成的表达示就为:
\d\u\{3}\d{3}.
从这里我们可以看到用这样的方式来查找要比第一种方法快得多.如果我们编辑的文件在采用这两种方法进行查找时会看出差别,那么我们的文件也许就是太大了.
我们还可以用这样的表达示:\d\u\u\u\d\d\d,这个也可以找到我们想要的内容.
最后我们还可以用字符类来写出我们的表达式:
[[:digit:]][[:upper:]]\{3}[[:digit:]]\{3}
这四种方法都可以很好的来完成我们的工作,我们只要记住一种我们容易记住的就可以了.毕竟我们可以记住的简单的方法要比我们不能记住的精妙的方法快得多啊.
到现在我们所有的讨论和方法都是在认为我们已经打开magic选项的基础上来做的.如果这个选项被关闭了,那么我们在通用表达式中的许多的特殊字符就失去了他们神奇的魔力,我们只有通过字符转义才可以正常的来使用.
关闭magic的选项命令为:
:set nomagic
这时*,.,[,]就都被认为只是平常的字符了.如果我们还想用*来指0次或是更多次就要用到转义:\*.
所以我们应保证magic选项是打开的,这样我们也才可以使用Vim强大的搜索能力,而这也正是Vim默认情况下所做的.
一些常用的偏移(Offset)定义:
+[num] 光标置于第一个匹配字符下第num行的开始处.
-[num] 光标置于第一个匹配字符上第num行的开始处.
e 匹配字符串的结尾处.
e[num]
光标置于第一个匹配字符串的结尾处,然后移动num个字符,如果为正,向右移,为负,向左移.
b s 第一个匹配字符串的开始处.
b[num]
s[num]
光标置于第一个匹配字符串的开始处,然后移动num个字符,如果为正,向右移,为负,向左移.
常用的通用表达式如下:(认为magic选项打开)
简单的元素:
x 字符x
^ 一行的开始处
$ 一行的结尾处.
. 单一的字符
\< 查找字符串的开始标记
\> 查找字符串的结束标记.
范围运算符:
[abc] 匹配a,b或是c
[^abc] 匹配除abc以处的字符
[a-z] 匹配从a到z的所有小写字符
[a-zA-Z] 匹配所有字符,包括大小写.
字符类:
[:alnum:] 匹配所有的字符和数字
[:alpha:] 匹配所有的字符
[:ascii:] 匹配所有的ASCII字符
[:backspace:] 匹配退格符<BS>
[:blank:] 匹配空格和Tab
[:cntrl:] 匹配所有的控制字符
[:digit:] 匹配所有的数字
[:escape:] 匹配Esc
[:graph:] 匹配所打印的字符,不包括空格
[:lower:] 匹配所有的小写字符
[:print:] 匹配所有的要打印字符,包括空格
[:return:] 匹配所有的行末符号(包括<Enter>,<CR>,<NL>).
[:punct:] 匹配所有的功能符号
[:space:] 匹配所有的空白符
[:tab:] 匹配Tab
[:upper:] 匹配所有的大写字符
[:xdigit:] 匹配十六进制数字.
类型:
\(pattern\) 标记一个类型以后使用
\1 与第一个在\(\)中的子表达式匹配的字符串匹配相同的字符串
例如表达式\([a-z]\)\1可以匹配aa,bb或是类似的.
\2 与\1相类似,但是是使用第二个子表达式
\9 与\1相类似,但是是使用第九个子表达式
特殊字符:
\a 大小写字母字符
\A 除了a-zA-Z以外的字母字符
\b <BS>
\d 数字字符
\D 非数字字符
\e <ESC>
\f 由isfname选项定义的文件名字符
\F 文件名字符,但是不包含数字
\h 单词的头字符(A-Za-z)
\H 不是单词的头字符(A-Za-z)
\i 由isdent选项定义的字符
\I 定义的字符,但是不包括数字
\k 由iskeyword选项定义的关键字字符
\K 关键字字符,但是不包括数字
\l 小字字符(a-z)
\L 非小写字符(除了a-z以外的字符)
\o 八进制数字
\O 非八进制数字
\p 由isprint选项定义的可打印字符
\P 可打印字符,但是不包括数字
\r <CR>
\s 空白符<Space>和<Tab>
\S 非空白符
\t <Tab>
\u 大写字母字符(A-Z)
\U 非大写字母字符
\w 单词字符(0-9A-Za-z)
\W 非单词字符
\x 十六进制数字
\X 非十六进制数字
\~ 匹配最后指定的字符串
修饰符:
* 匹配0次或是多次,尽可能多的匹配
\+ 匹配1次或是多次,尽可能多的匹配
\= 匹配0次或是1次
\{} 匹配0次或是多次
\{n}
\{-n} 匹配n次
\{n,m} 匹配n次到m次
\{n,} 匹配n次到多次
\{,m} 匹配0次到m次
\{-n,m} 匹配n次到m次,尽可能少的进行匹配
\{-n,} 至少匹配n次,尽可能少的进行匹配
\{-,m} 匹配到m次,尽可能少的进行匹配
\{-} 匹配0次到多次,尽可能少的进行匹配
str1\|str2 匹配str1或是str2