使用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 ++。
感谢您的建议。
答案 0 :(得分:3)
我可能会为此投票!
我是狂热的(G)VIM用户,但当我想查看或理解某些代码时,我会使用Source Insight。我几乎从不使用它作为一个真正的编辑器。
在这种情况下,它完全符合您的要求,例如在关系窗口中显示使用某些突出显示的数据类型/ define / constant / etc ...的所有函数/方法......
(来源: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插件。它将打开一个搜索窗口,这样您就可以看到搜索发生的整行,并自动跳转到它。给出了一个很好的概述。
(来源: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)
Ctags 1也可能对您有用。它可以为项目生成标记文件。此标记文件允许用户直接从函数调用跳转到它的定义,即使它在使用“CTRL +]”的另一个文件中。