在一篇广为流传的"正则表达式之道"的文章中有下面的例子.
这里有几行我们现在的数据:
Bill Jones, HI-TEK Corporation , CA, 95011
Sharon Lee Smith, Design Works Incorporated, CA, 95012
B. Amos , Hill Street Cafe, CA, 95013
Alexander Weatherworth, The Crafts Store, CA, 95014
...
我们希望把它变成这个样子:
Bill Jones,CA 95011,HI-TEK Corporation
Sharon Lee Smith,CA 95012,Design Works Incorporated
B. Amos,CA 95013,Hill Street Cafe
Alexander Weatherworth,CA 95014,The Crafts Store
说有两个正则表达式即可实现这样的神奇功效:
其一:
:%s/\([^,]*\),\([^,]*\),\([^,]*\),\(.*\)/\1,\3 \4,\2/
其二:
:%s/[ \t]*,[ \t]*/,/g
这个方法有个不易觉察的小瑕疵:
如果末尾的95011后面有一个看不到的空白字符, 则这些空白字符并不能被有效地去除.
其实在VIM中有更好的解法:
%s#\s*\([^,]\{-}\)\s*,\s*\([^,]\{-}\)\s*,\s*\([^,]\{-}\)\s*,\s*\([^,]\{-}\)\s*$#\1,\3 \4,\2
好处有下面几个:
使用/之外的字符作为正则表达式的分隔符, 可以使/和\不那么迷惑
\{-} 使得匹配不再是"贪婪"模式, 这对于需要大量回溯运算的例子会极大提高性能.
\s代替了[ \t], 更为简练一些.
作为现实中对正则表达式的使用, 象这样的情况你不能不考虑这个表达式本身的复杂程度和正确写出它你所要花费的成本, 考虑到中间的 \s*\([^,]\{-}\)\s*, 反复出现几次
你当然可以这样来构造它
%s#
\s*\([^,]\{-}\)\s*,
然后用简单的 Y/3p 操作来构造出完整的4个部分
%s#
\s*\([^,]\{-}\)\s*,
\s*\([^,]\{-}\)\s*,
\s*\([^,]\{-}\)\s*,
\s*\([^,]\{-}\)\s*,对最后一个略加修改
\s*\([^,]\{-}\)\s*, ==> \s*\([^,]\{-}\)\s*$,
这是因为\{-}如果仍以保守而含蓄的方式工作的话, 最后一个,后面的部分将被最少量地匹配, 而加了\s*$之后, 使得它得以匹配行尾之前的所有非空白字符.
当然, 最后一部分的末尾的逗号不需要
最终构造出来的是:
%s#
\s*\([^,]\{-}\)\s*,
\s*\([^,]\{-}\)\s*,
\s*\([^,]\{-}\)\s*,
\s*\([^,]\{-}\)\s*$
#\1,\3 \4,\2
当然, 上面这些都是在VIM的一个缓冲区中编辑的, 怎么有效地把它放到命令行上呢, 这里最需要的不出错.
:%j!
这个命令可以把上面这个复杂的正则表达式的不同部分粘连到一个命令行上
%s#\s*\([^,]\{-}\)\s*,\s*\([^,]\{-}\)\s*,\s*\([^,]\{-}\)\s*,\s*\([^,]\{-}\)\s*$#\1,\3 \4,\2
如果是在WINDOWS下使用, 你当然可以借助来做, 但在VIM中有更通用的办法:
将整个正则表达式的内容放到一个寄存器中, 具体做法是在NORMAL模式下, 用^定位到行首, 再以"xy$把到行尾的全部内容放入寄存器x中, 然后用:进入命令行模式, 键入x 它会把寄存器x的内容插入到当前位置, 这样命令行上就会准确地出现你精心打造出来的命令.
阅读(1117) | 评论(0) | 转发(0) |