Как найти функции в файле cpp, содержащие определенное слово
Вопрос
используя grep, grep vim или другую команду оболочки Unix, я хотел бы найти функции в большом файле cpp, которые содержат определенное слово в своем теле.
В файлах, с которыми я работаю, искомое слово находится в строке с отступом, соответствующий заголовок функции — это первая строка над строкой с отступом, которая начинается с позиции 0 и не является символом «{».
Например, поиск JOHN_DOE в следующем фрагменте кода.
int foo ( int arg1 )
{
/// code
}
void bar ( std::string arg2 )
{
/// code
aFunctionCall( JOHN_DOE );
/// more code
}
должен дать мне
void bar ( std::string arg2 )
Алгоритм, который я надеюсь уловить в сценариях оболочки grep/vim/unix, вероятно, лучше всего будет использовать предположения об отступах и форматировании, а не пытаться анализировать C/C++.
Спасибо за ваши предложения.
Решение
Насколько я знаю, это невозможно сделать. И вот почему:
Во-первых, вы должны искать между строками. Нет проблем, в vim добавление _ к символьному классу говорит ему включать новые строки. поэтому {_. *} будет соответствовать всему, что находится в скобках в нескольких строках.
Итак, теперь вам нужно сопоставить любой шаблон для заголовка функции (хрупкий, даже если вы заставите его работать), и вот в чем проблема, между строками и строкой поиска > и, наконец, соответствует строке поиска. Таким образом, вы можете иметь регулярное выражение вроде
/^\(void \+\a\+ *(.*)\)\_.*JOHN_DOE
Но что происходит, когда vim в первый раз находит заголовок функции и начинает сопоставление. Затем он соответствует каждому символу , пока не найдет JOHN_DOE. Который включает в себя все заголовки функций в файле. Р>
Итак, проблема в том, что, насколько я знаю, нет никакого способа сказать vim, что он соответствует каждому символу, за исключением этого шаблона регулярных выражений. И даже если бы и было, регулярное выражение не является инструментом для этой работы. Это как открыть пиво молотком. Что мы должны сделать, это написать простой скрипт, который даст вам эту информацию, и у меня есть.
fun! FindMyFunction(searchPattern, funcPattern)
call search(a:searchPattern)
let lineNumber = line(".")
let lineNumber = lineNumber - 1
"call setpos(".", [0, lineNumber, 0, 0])
let lineString = getline(lineNumber)
while lineString !~ a:funcPattern
let lineNumber = lineNumber - 1
if lineNumber < 0
echo "Function not found :/"
endif
let lineString = getline(lineNumber)
endwhile
echo lineString
endfunction
Это должно дать вам желаемый результат, и гораздо проще поделиться, отладить и повторно использовать, чем выплевывать регулярные выражения из уст самого Ктулху.
Другие советы
Меня, вероятно, проголосуют за это!
Я заядлый пользователь (G)VIM, но когда я хочу просмотреть или понять какой-то код, я использую Источник.Однако я почти никогда не использую его в качестве настоящего редактора.
В этом случае он делает именно то, что вы хотите, например.показать все функции/методы, которые используют какой-либо выделенный тип данных/определить/константу/и т.д...в окне отношений...
(источник: sourceinsight.com)
Ой!Вот и моя репутация.
Сложный вызов, хотя в качестве отправной точки я бы предложил этот замечательный учебник по VIM Regex . р>
Вы не можете делать это надежно с помощью регулярного выражения, потому что код не является регулярным языком. Вам нужен настоящий анализатор для рассматриваемого языка.
Ааа!Я признаю, что это немного перебор:
Небольшая программа для фильтрации стандартного ввода, удаления комментариев и размещения тел функций в одной строке.Помимо прочего, его обманут пространства имен и определения функций внутри объявлений классов.Но это может быть хорошим началом:
#include <stdio.h>
#include <assert.h>
int main() {
enum {
NORMAL,
LINE_COMMENT,
MULTI_COMMENT,
IN_STRING,
} state = NORMAL;
unsigned depth = 0;
for(char c=getchar(),prev=0; !feof(stdin); prev=c,c=getchar()) {
switch(state) {
case NORMAL:
if('/'==c && '/'==prev)
state = LINE_COMMENT;
else if('*'==c && '/'==prev)
state = MULTI_COMMENT;
else if('#'==c)
state = LINE_COMMENT;
else if('\"'==c) {
state = IN_STRING;
putchar(c);
} else {
if(('}'==c && !--depth) || (';'==c && !depth)) {
putchar(c);
putchar('\n');
} else {
if('{'==c)
depth++;
else if('/'==prev && NORMAL==state)
putchar(prev);
else if('\t'==c)
c = ' ';
if(' '==c && ' '!=prev)
putchar(c);
else if(' '<c && '/'!=c)
putchar(c);
}
}
break;
case LINE_COMMENT:
if(' '>c)
state = NORMAL;
break;
case MULTI_COMMENT:
if('/'==c && '*'==prev) {
c = '\0';
state = NORMAL;
}
break;
case IN_STRING:
if('\"'==c && '\\'!=prev)
state = NORMAL;
putchar(c);
break;
default:
assert(!"bug");
}
}
putchar('\n');
return 0;
}
Это C++, поэтому просто сохраните его в файле, скомпилируйте его в файл с именем «стриппер», а затем:
cat my_source.cpp | ./stripper | grep JOHN_DOE
Итак, рассмотрим ввод:
int foo ( int arg1 )
{
/// code
}
void bar ( std::string arg2 )
{
/// code
aFunctionCall( JOHN_DOE );
/// more code
}
Вывод "cat example.cpp | ./stripper
" является:
int foo ( int arg1 ) { }
void bar ( std::string arg2 ){ aFunctionCall( JOHN_DOE ); }
Вывод "cat example.cpp | ./stripper | grep JOHN_DOE
" является:
void bar ( std::string arg2 ){ aFunctionCall( JOHN_DOE ); }
Задача по поиску имени функции (угадайте, что это последний идентификатор, предшествующий "(
") оставлено читателю в качестве упражнения.
Для такого рода вещей, хотя это снова касается примитивного поиска, я бы рекомендовал плагин compview . Откроется окно поиска, так что вы сможете увидеть всю строку, где произошел поиск, и автоматически перейти к ней. Дает хороший обзор.
(источник: axisym3.net ) р>
Как сказал Роберт, Regex поможет. В командном режиме запустите поиск по регулярному выражению, набрав " / " символ, за которым следует ваше регулярное выражение.
Ctags 1 также могут быть вам полезны. Он может генерировать файл тегов для проекта. Этот файл тегов позволяет пользователю переходить непосредственно от вызова функции к его определению, даже если он находится в другом файле с использованием " CTRL +] ".
ты можешь использовать grep -r -n -H JOHN_DOE *
он будет искать «JOHN_DOE» в файлах рекурсивно, начиная с текущего каталога.
вы можете использовать следующий код, чтобы практически найти функцию, содержащую текстовое выражение:
public void findFunction(File file, String expression) {
Reader r = null;
try {
r = new FileReader(file);
} catch (FileNotFoundException ex) {
ex.printStackTrace();
}
BufferedReader br = new BufferedReader(r);
String match = "";
String lineWithNameOfFunction = "";
Boolean matchFound = false;
try {
while(br.read() > 0) {
match = br.readLine();
if((match.endsWith(") {")) ||
(match.endsWith("){")) ||
(match.endsWith("()")) ||
(match.endsWith(")")) ||
(match.endsWith("( )"))) {
// this here is because i guessed that method will start
// at the 0
if((match.charAt(0)!=' ') && !(match.startsWith("\t"))) {
lineWithNameOfFunction = match;
}
}
if(match.contains(expression)) {
matchFound = true;
break;
}
}
if(matchFound)
System.out.println(lineWithNameOfFunction);
else
System.out.println("No matching function found");
} catch (IOException ex) {
ex.printStackTrace();
}
}
я написал это на JAVA, протестировал и работает как шарм.Хотя у него мало недостатков, но для начала все в порядке.не добавлена поддержка нескольких функций, содержащих одно и то же выражение и, возможно, некоторые другие вещи.попробуй это.