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

3

我目前在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 WITH WORD UNDER CURSOR
function! SubstituteProjectwideNormal()
  let wordUnderCursor = expand("<cword>")
  call SubsituteProjectwide(wordUnderCursor)
endfunction
:nnoremap <F6> :call SubstituteProjectwideNormal()<cr>

" GETTING THE FILES W## Heading ##ICH 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://dev59.com/snI_5IYBdhLWcg3wFu7L
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个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
5
要进行字面替换,需要指定"very-nomagic"(:help /\V),并在源代码中转义分隔符(/)和\。 在替换文本中,如果设置了'magic'选项,则必须对&~进行转义(此处不适用于\V)。请注意保留HTML标记。
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'

它似乎运行正常。我需要用一些更复杂的搜索条件来测试它。 - divramod
@divramod 请记住,您还需要转义&~,至少在替换模式中。请参考@ingo-karkat答案中最后一行的结尾。 - dash-tom-bang

1
这并不完全回答你的问题,但可以另一种方式来看待你试图解决的问题。我不完全明白:args设置对你有什么作用,因为在:vimgrep之后,quickfix已经提供了你所需的所有信息。 我在我的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,它就会不断调用自身,直到完成。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,