如何在cpp文件中查找包含特定单词的函数

时间:2009-05-06 13:03:09

标签: grep vim

使用grep,vim的grep或其他unix shell命令,我想在大型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 shell脚本中捕获的算法可能最好使用缩进和格式化假设,而不是尝试解析C / C ++。

感谢您的建议。

8 个答案:

答案 0 :(得分:3)

我可能会为此投票!

我是狂热的(G)VIM用户,但当我想查看或理解某些代码时,我会使用Source Insight。我几乎从不使用它作为一个真正的编辑器。

在这种情况下,它完全符合您的要求,例如在关系窗口中显示使用某些突出显示的数据类型/ define / constant / etc ...的所有函数/方法......

gif of the relations window from the source insight website
(来源:sourceinsight.com

哎哟!我的代表。

答案 1 :(得分:2)

据我所知,这是不可能做到的。原因如下:

首先,您必须跨行搜索。没问题,在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

这应该会给你你想要的结果,而且比Cthulhu本人口中的正则表达式更容易分享,调试和重新利用。

答案 2 :(得分:1)

艰难的电话,虽然作为一个起点我会建议这个很棒VIM Regex Tutorial

答案 3 :(得分:1)

使用正则表达式无法可靠地执行此操作,因为代码不是常规语言。你需要一个真正的语言解析器。

答案 4 :(得分:1)

对于那种东西,虽然它再次进行原始搜索,但我会推荐compview插件。它将打开一个搜索窗口,这样您就可以看到搜索发生的整行,并自动跳转到它。给出了一个很好的概述。

alt text
(来源:axisym3.net

答案 5 :(得分:1)

Arggh!我承认这有点过头了:

一个小程序,用于过滤stdin,剥离注释,并将函数体放在同一行上。除了其他事情之外,它还会被类声明中的命名空间和函数定义所迷惑。但这可能是一个好的开始:

#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 ++,所以只需在文件中,将其编译为名为'stripper'的文件,然后:

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 ); }

找到函数名称(猜测它是“(”之前的最后一个标识符)的工作留给了读者。

答案 6 :(得分:0)

你可以使用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中写过这个,测试它并且像魅力一样工作。虽然有一些缺点,但对于初学者来说这很好。没有添加对包含相同表达式的多个函数的支持,也许还有其他一些东西。试试吧。

答案 7 :(得分:0)

像罗伯特一样,Regex会提供帮助。在命令模式下,通过键入“/”字符后跟正则表达式来启动正则表达式搜索。

Ctags 1也可能对您有用。它可以为项目生成标记文件。此标记文件允许用户直接从函数调用跳转到它的定义,即使它在使用“CTRL +]”的另一个文件中。