Vim在C / C ++代码行中搜索

时间:2010-04-21 13:58:12

标签: vim

有没有办法在跳过注释行的同时搜索C / C ++源文件中的字符串?

4 个答案:

答案 0 :(得分:29)

这是一个有趣的问题。

我认为@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

搜索hello,但仅在Vim认为是字符串的文本中搜索。

并且(最后!)这会在除评论之外的任何地方搜索double

:SearchOutside Comment double

要重复搜索,请使用@:宏重复执行相同的命令,例如按n重复搜索。

(顺便提一下,谢谢你提出这个问题。既然我已经建立了这些例程,我希望能够使用它们。)

答案 1 :(得分:6)

此模式搜索不在两个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*\*[^/]).*)@<!

答案 2 :(得分:1)

不确定这是否有用,但是当您键入:syn时,它具有您的文件类型中使用的所有格式。也许你可以某种方式参考。你可以这样说:

map n betterN

function betterN{
  n keystroke
  while currentLine matches comment class
    do another n keystroke
}

答案 3 :(得分:0)

以下是我将如何继续:

  1. 删除所有C / C ++注释(使用替换命令%s
  2. 使用常规搜索命令/
  3. 继续进行搜索
  4. 使用m a在该位置设置标记(设置标记“a”)
  5. 使用u
  6. 撤消删除评论
  7. 使用``a`
  8. 跳转到标记“a”
  9. 最终使用delm a删除标记(如果您不删除标记,则会被覆盖,所以没什么大不了的)
  10. 当然,你可以在一个大的操作/功能中做到这一点。我没有掌握Vim脚本的好处,但是给出了一个例子。

    我承认我的解决方案有点“懒惰”(你可能会更好地方式),但这就是我的全部。

    希望它有所帮助。