vim:转义字符串替换(vimscript)

时间:2017-09-15 08:20:15

标签: vim escaping substitution

我目前正在编写一个替代函数,我经常需要在vim中进行编程。

我已经写过的函数看起来像这样,并且基本上可以运行来搜索和替换里面没有任何特殊字符的字符串。我已经意识到要自动逃避“/”。我的问题是,我如何调整行中的escape()函数

execute ':silent :argdo %s/' . escape(searchPattern, '/') . '/' . escape(replacePattern, '/') . '/ge'

这样,所有必须转义的角色都会被自动转义吗?

" MAIN FUNCTION
" inspired by http://vimcasts.org/episodes/project-wide-find-and-replace/
function! SubstituteProjectwide(searchInput)
  :set hidden
  let cwd = getcwd()
  let filename=expand('%:p')
  call inputsave()
  let searchPattern = input('Search for: ', a:searchInput)
  let replacePattern = input('Replace "' . searchPattern . '" with: ')
  let filePattern = input('Filepattern: ', cwd . '/**/*.*')
  call inputrestore()
  execute ':silent :args ' . filePattern
  execute ':silent :vimgrep /' . searchPattern . '/g ##'
  execute ':silent :Qargs'
  execute ':silent :argdo %s/' . escape(searchPattern, '/\') . '/' . escape(replacePattern, '/\') . '/ge'
  execute ':silent :edit ' . filename
  echo 'Replaced "' . searchPattern . '" with "' . replacePattern . '" in ' . filePattern
endfunction

" VISUAL ENTRYPOINT WITH SELECTED TEXT
function! SubstituteProjectwideVisual()
  let v = @*
  call SubstituteProjectwide(GetVisualSelectedText())
endfunction
:vnoremap <F6> :call SubstituteProjectwideVisual()<cr>

" NORMAL ENTRYPOINT WIHT WORD UNDER CURSOR
function! SubstituteProjectwideNormal()
  let wordUnderCursor = expand("<cword>")
  call SubsituteProjectwide(wordUnderCursor)
endfunction
:nnoremap <F6> :call SubstituteProjectwideNormal()<cr>

" GETTING THE FILES WICH CONTAIN SEARCH PATTERN
" copied from http://vimcasts.org/episodes/project-wide-find-and-replace/
command! -nargs=0 -bar Qargs execute 'args' QuickfixFilenames()
function! QuickfixFilenames()
  let buffer_numbers = {}
  for quickfix_item in getqflist()
    let buffer_numbers[quickfix_item['bufnr']] = bufname(quickfix_item['bufnr'])
  endfor
  return join(map(values(buffer_numbers), 'fnameescape(v:val)'))
endfunction

" GETTING THE CURRENT VISUAL SELECTION
" copied from: https://stackoverflow.com/questions/1533565/how-to-get-visually-selected-text-in-vimscript
function! GetVisualSelectedText()
  let [line_start, column_start] = getpos("'<")[1:2]
  let [line_end, column_end] = getpos("'>")[1:2]
  let lines = getline(line_start, line_end)
  if len(lines) == 0
    return ''
  endif
  let lines[-1] = lines[-1][: column_end - (&selection == 'inclusive' ? 1 : 2)]
  let lines[0] = lines[0][column_start - 1:]
  return join(lines, "\n")
endfunction

更新

我设法逃脱了许多这样的角色

escape(searchPattern, ' / \') . '/' . escape(replacePattern, ' / \')

但是,如果基本上可以的话,我怎么知道我必须逃避哪个字符列表,每个字符都可以在搜索内部以及替换字符串?

2 个答案:

答案 0 :(得分:1)

要执行字面替换,请指定&#34;非常无意义的&#34; (:help /\V),然后转义分隔符(/)和\ 在源头。

如果设置了&选项,则在替换中,~'magic'也必须进行转义。 (\V在这里不起作用。)

execute ':silent :argdo %s/\V' . escape(searchPattern, '/\') . '/' . escape(replacePattern, '/\' . (&magic ? '&~' : '')) . '/ge'

换行符(如果可能)必须从^M更改为\n

execute ':silent :argdo %s/\V' . substitute(escape(searchPattern, '/\'),"\n",'\\n','ge') . '/' . escape(replacePattern, '/\' . (&magic ? '&~' : '')) . '/ge'

答案 1 :(得分:1)

这并不能完全回答您的问题,而是另一种看待您尝试解决的问题的方法。我并不完全遵循:args设置为您做的事情,因为quickfix在:vimgrep之后具有您需要的所有信息。

我在我的vimrc中有这个:

nnoremap <F3> :vimgrep // $PROJECT_ROOT_DIR/src/**/*.{cpp,h,c,inl,msg}<C-Left><C-Left><Right>

显然,您需要自定义搜索路径,因为这只关注每次启动Vim时配置的特定文件层次结构中的上述五个文件扩展名...

无论如何,一旦你得到了它,:cr确保你在开头,然后在宏内进行搜索和替换。如果你愿意的话,你可以在前几个发现中测试它,但是......

qbq清除'b'寄存器。

qa开始录制'a'宏'

:%s/this/that/g启动宏并将'that'替换为'this'。 (按回车键)

:w|cnf写下文件并转到下一个文件(按回车键)

q停止录制'a'宏。

然后qb@a@bq将运行宏一次,将其保存在@b中。然后跑吧 (再次输入@b,它会一直调用,直到完成为止。