目录
前言
vim 的搜索和替换功能强大突破天际, 但是正则语法实在怪异, 既不像平常熟知的 perl 风格, 也不像 grep 风格, 每次都记不住语法
先来体验一下两者的巨大差别:
perl 风格:
(ab+?c)(?!ing)
vim 风格:
\(ab\{-1,}c\)\%(ing\)\@!/
于是某Z 坐不住了打算定制一下
buffer 内搜索和替换
这个有现成的好用的东西了, 使用 othree/eregex.vim 即可
顺便映射几个按键比较符合个人习惯:
nnoremap / /\v
nnoremap ? :M/
nnoremap <leader>vf :M/<c-r><c-w>
nnoremap <leader>vr :.,$S///gec<left><left><left><left><left>
关于 \v
可以 :h magic
没有直接映射到 /
上, 是因为这货不支持 incsearch
另外, 这货也直接支持 :G
和 :V
命令
sort
vim 自带的 :sort
功能非常强大, 可以用正则来指定排序规则
所以, 我们也可以用 eregex 来包装一下
function! ZF_Plugin_eregex_sort(bang, line1, line2, args)
let cmd = a:line1 . ',' . a:line2 . 'sort' . a:bang . ' '
if len(a:args) <= 0 || a:args[0] != '/'
let cmd .= a:args
else
let match = matchstrpos(a:args, '\%(/\)\@<=.*\%(/\)\@=')
if match[1] >= 0
let cmd .= '/' . E2v(match[0]) . '/ ' . strpart(a:args, match[2] + 1)
else
let cmd .= '/' . E2v(strpart(a:args, 1)) . '/'
endif
endif
execute cmd
endfunction
command! -nargs=* -range=% -bang Sort :call ZF_Plugin_eregex_sort('<bang>', <line1>, <line2>, <q-args>)
使用方法和默认的 :sort
完全一样
全工程搜索和替换
试用过很多 vim 全工程搜索替换的插件, 最终还是 dkprice/vim-easygrep 最适合我
grep 本身也支持添加 -P
参数来使用 perl 风格正则表达式, 可惜 easygrep 没有支持, 于是本人又坐不住稍微修改了下
(原 repo 已合并该功能, 参见 这里)
使用方法很简单:
-
需要安装 othree/eregex.vim 插件
-
添加以下设置:
set grepprg=grep\ -n\ $*\ /dev/null let g:EasyGrepCommand=1 let g:EasyGrepPerlStyle=1
-
然后正常的使用
:Grep
和:Replace
即可
注意事项:
- Windows 下需要安装 cygwin 并且添加 cygwin/bin 的路径到系统 PATH 里面 (MinGW 没试过, 应该也行)
-
grep 必须是 2.5.3 以上的 GNU 版本
mac 下默认是 BSD 版本, 不支持 perl 风格正则, 所以必须手动安装 GNU 版本
可以使用 brew 进行安装, 也可以自行下载 grep 源码编译, 具体请自行 Google 吧
多行正则搜索
有时候还是需要跨行进行正则搜索 (例如 aaa.*\n.*bbb
), 然而 grep
并不支持这个, 所幸我们还有 pcregrep
,
这边顺便提供一个个人的配置, 保持和 easygrep
的使用习惯一致, 不过只支持查找不支持替换
function! ZF_Plugin_easygrep_pcregrep(expr)
let expr = a:expr
let expr = substitute(expr, '"', '\\"', 'g')
let cmd = 'pcregrep --buffer-size=16M -M -r -s -n'
if match(expr, '\C[A-Z]') < 0
let cmd .= ' -i'
endif
let ignoreList = split(g:EasyGrepFilesToExclude, ',')
for ignore in ignoreList
let ignore = substitute(ignore, '\.', '\\.', 'g')
let ignore = substitute(ignore, '\*', '.*', 'g')
let cmd .= ' --exclude-dir="' . ignore . '"'
let cmd .= ' --exclude="' . ignore . '"'
endfor
let cmd .= ' "' . expr . '" *'
let result = system(cmd)
let qflist = []
let vim_pattern = E2v(a:expr)
for line in split(result, '\n')
let file = substitute(matchstr(line, '^[^:]\+:'), ':', '', 'g')
let file_line = substitute(matchstr(line, ':[0-9]\+:'), ':', '', 'g')
if strlen(file) <= 0 || strlen(file_line) <= 0
continue
endif
let text = substitute(line, '^\[^:\]*:\[^:\]*:\(.*\)$', '\1', 'g')
let qflist += [{
\ 'filename' : file,
\ 'lnum' : file_line,
\ 'text' : text,
\ 'pattern' : vim_pattern,
\ }]
endfor
call setqflist(qflist)
if len(qflist) > 0
execute ':silent! M/' . a:expr
copen
else
echo 'no matches for: ' . a:expr
endif
endfunction
command! -nargs=+ ZFGrepExt :call ZF_Plugin_easygrep_pcregrep(<q-args>)
try
if match(system('pcregrep --version'), '[0-9]\+\.[0-9]\+') < 0
nnoremap <leader>vge :echo 'pcregrep not installed'<cr>
else
nnoremap <leader>vge :ZFGrepExt<space>
endif
endtry
转载请注明来自: http://zsaber.com/blog/p/73
既然都来了, 有啥想法顺便留个言呗? (无奈小广告太多, 需审核, 见谅)
谢谢,以前在一文章中看到搜索时使用perl风格正则,忘了后就一直没搜索到使用方式,今天终于在你这找到了,实在是无法适应VIM自身的正则风格