Как найти функции в файле cpp, содержащие определенное слово

StackOverflow https://stackoverflow.com/questions/829447

  •  06-07-2019
  •  | 
  •  

Вопрос

используя 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, но когда я хочу просмотреть или понять какой-то код, я использую Источник.Однако я почти никогда не использую его в качестве настоящего редактора.

В этом случае он делает именно то, что вы хотите, например.показать все функции/методы, которые используют какой-либо выделенный тип данных/определить/константу/и т.д...в окне отношений...

gif of the relations window from the source insight website
(источник: 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 . Откроется окно поиска, так что вы сможете увидеть всю строку, где произошел поиск, и автоматически перейти к ней. Дает хороший обзор.

 alt text
(источник: 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, протестировал и работает как шарм.Хотя у него мало недостатков, но для начала все в порядке.не добавлена ​​поддержка нескольких функций, содержащих одно и то же выражение и, возможно, некоторые другие вещи.попробуй это.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top