Есть ли способ поиска строки в исходном файле C/С++ при пропуске прокомментированных строк?
Поиск Vim в строках кода C/С++
Ответ 1
Это интригующий вопрос.
Я думаю, что у @sixtyfootersdude есть правильная идея - пусть подсветка синтаксиса Vim скажет вам, что комментарий, а что нет, а затем ищите совпадения в не-комментариях.
Начнем с функции, которая имитирует встроенную подпрограмму search()
Vim, но также предоставляет параметр "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
, чтобы повторить поиск.
(Спасибо, что задали этот вопрос, между прочим. Теперь, когда я создал эти подпрограммы, я ожидаю, что они будут использовать их много.)
Ответ 2
Этот шаблон ищет строку, которой не предшествуют две соглашения о комментариях на С++. Я также исключил "*" в качестве первого символа без пробелов, поскольку это общее соглашение для многострочных комментариев.
/\(\(\/\*\|\/\/\|^\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*\*[^/]).*)@<!
Ответ 3
Не уверен, что это полезно, но при вводе :syn
у него есть все форматирование, которое используется в вашем типе файла. Может быть, вы можете как-то сослаться на это. Вы могли бы сказать что-то вроде:
map n betterN
function betterN{
n keystroke
while currentLine matches comment class
do another n keystroke
}
Ответ 4
Вот как я буду продолжать:
- Удалить все комментарии C/С++ (с помощью команды replace
%s
) - Перейдите к поиску с помощью обычной команды поиска
/
- Установите отметку в позиции с помощью
m a
(чтобы установить отметку "a" ) - Отмените удаление комментариев с помощью
u
- Перейти к значению "a" с помощью `` a`
- В конце концов удаление метки с помощью
delm a
(она будет перезаписана в случае, если вы ее не удалите, так что неважно)
Конечно, вы можете сделать это в одной большой операции/функции. Я не разбираюсь в сценариях Vim достаточно хорошо, чтобы показать пример этого.
Я признаю, что мое решение немного "лениво" (и вы, вероятно, можете сделать это лучше), но все, к чему я пришел.
Надеюсь, что это поможет.