读书人

大家伙儿VIM(一久新的

发布时间: 2012-06-29 15:48:46 作者: rapoo

大家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/\(.\)\(.\)r\2\1/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/\u\d\d\d\d\d\d\d\d\d\>/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) 一。

读书人网 >开源软件

热点推荐