是否有一种方法可以在C / C ++源文件中搜索字符串,同时跳过注释的行?
这是一个有趣的问题。
我认为@sixtyfootersdude的想法是正确的——让Vim的语法高亮告诉你什么是注释,什么不是注释,然后在非注释中搜索匹配项。
让我们从一个函数开始,该函数模仿Vim内置的search()
例程,但还提供了一个“skip”参数来忽略一些匹配项:
function! SearchWithSkip(pattern, flags, stopline, timeout, skip)
"
" Returns true if a match is found for {pattern}, but ignores matches
" where {skip} evaluates to false. This allows you to do nifty things
" like, say, only matching outside comments, only on odd-numbered lines,
" or whatever else you like.
"
" Mimics the built-in search() function, but adds a {skip} expression
" like that available in searchpair() and searchpairpos().
" (See the Vim help on search() for details of the other parameters.)
"
" Note the current position, so that if there are no unskipped
" matches, the cursor can be restored to this location.
"
let l:matchpos = getpos('.')
" Loop as long as {pattern} continues to be found.
"
while search(a:pattern, a:flags, a:stopline, a:timeout) > 0
" If {skip} is true, ignore this match and continue searching.
"
if eval(a:skip)
continue
endif
" If we get here, {pattern} was found and {skip} is false,
" so this is a match we don't want to ignore. Update the
" match position and stop searching.
"
let l:matchpos = getpos('.')
break
endwhile
" Jump to the position of the unskipped match, or to the original
" position if there wasn't one.
"
call setpos('.', l:matchpos)
endfunction
SearchWithSkip()
基础上实现语法敏感搜索的一些功能:function! SearchOutside(synName, pattern)
"
" Searches for the specified pattern, but skips matches that
" exist within the specified syntax region.
"
call SearchWithSkip(a:pattern, '', '', '',
\ 'synIDattr(synID(line("."), col("."), 0), "name") =~? "' . a:synName . '"' )
endfunction
function! SearchInside(synName, pattern)
"
" Searches for the specified pattern, but skips matches that don't
" exist within the specified syntax region.
"
call SearchWithSkip(a:pattern, '', '', '',
\ 'synIDattr(synID(line("."), col("."), 0), "name") !~? "' . a:synName . '"' )
endfunction
command! -nargs=+ -complete=command SearchOutside call SearchOutside(<f-args>)
command! -nargs=+ -complete=command SearchInside call SearchInside(<f-args>)
经过漫长的探索,我们现在可以做出这样的事情:
:SearchInside String hello
这会在Vim认为是字符串的文本中搜索hello
。
最后,这会在除注释外的所有地方搜索double
:
:SearchOutside Comment double
@:
宏来重复执行相同的命令,就像按下n
键重复搜索一样。这个模式搜索不以两种C++注释约定为前缀的字符串。我还排除了 '*' 作为第一个非空白字符,因为这是多行注释的常见约定。
/\(\(\/\*\|\/\/\|^\s*\*[^/]\).*\)\@<!foo
只有第一个和第四个foo会被匹配。
foo
/* foo
* baz foo
*/ foo
// bar baz foo
在模式的开头加上 \v 可以消除许多反斜杠:
/\v((\/\*|\/\/|^\s*\*[^/]).*)@<!foo
你可以在你的 .vimrc 文件中添加以下内容,将快捷键绑定到该模式:
"ctrl+s to search uncommented code
noremap <c-s> <c-o>/\v((\/\*\|\/\/\|^\s*\*[^/]).*)@<!
不确定这是否有帮助,但当您键入:syn
时,它具有文件类型中使用的所有格式。也许您可以从中参考一些内容。您可以说类似于:
map n betterN
function betterN{
n keystroke
while currentLine matches comment class
do another n keystroke
}
这是我的处理方法:
%s
)/
进行搜索m a
设置标记位置(设置标记“a”)u
撤销注释的删除delm a
删除标记(如果不删除,它会被覆盖,所以没关系)当然,你也可以将其作为一个大型操作/函数来完成。我并不精通Vim脚本,无法给出示例。
我承认我的解决方案有点“懒惰”(而且你可能可以做得更好),但这就是我能想到的。
希望对你有所帮助。
let l:guard = []
。然后在循环内部添加代码:if l:guard == [] | let l:guard = getpos('.') | elseif l:guard == getpos('.') | break | endif
。 - Kurt Hutchinsonlet l:flags = a:flags
,将搜索调用更改为l:flags
,并在if l:firstmatch == []
中添加一行代码,如下所示:let l:flags = substitute(l:flags, 'c', '', '')
。 - JelteF