5

grep、vimのgrep、または別の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 ++を解析しようとするよりも、インデントとフォーマットの仮定を使用するのがおそらく最善でしょう。

あなたの提案をありがとう。

4

8 に答える 8

3

私はおそらくこれに投票されるでしょう!

私は熱心な(G)VIMユーザーですが、コードを確認または理解したい場合は、SourceInsightを使用します。しかし、実際のエディターとして使用することはほとんどありません。

これは、この場合に必要なことを正確に実行します。たとえば、強調表示されたデータ型/定義/定数などを使用するすべての関数/メソッドをリレーションウィンドウに表示します。

ソースインサイトWebサイトのリレーションウィンドウのgif
(出典:sourceinsight.com

痛い!私の担当者が行きます。

于 2009-05-07T10:13:17.670 に答える
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

それはあなたが望む結果を与えるはずであり、クトゥルフ自身の口から吐き出される正規表現よりも共有、デバッグ、および再利用がはるかに簡単です。

于 2009-05-06T18:09:25.910 に答える
1

厳しい呼びかけですが、出発点として、この素晴らしいVIM正規表現チュートリアルをお勧めします。

于 2009-05-06T13:11:37.860 に答える
1

コードは正規言語ではないため、正規表現ではこれを確実に行うことはできません。問題の言語の実際のパーサーが必要です。

于 2009-05-06T13:32:51.957 に答える
1

そのようなものについては、再び原始的な検索になりますが、私はcompviewプラグインをお勧めします。検索ウィンドウが開くので、検索が行われた行全体を確認して、自動的にその行にジャンプできます。素晴らしい概要を示します。

代替テキスト
(出典:axisym3.net

于 2009-05-06T13:55:43.180 に答える
1

ああ!私はこれが少し上にあることを認めます:

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

関数名を見つける作業(「(」の前にある最後の識別子を推測する)は、読者の練習問題として残されています。

于 2009-05-06T19:18:21.033 に答える
0

uは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で作成し、テストして、チャームのように機能します。欠点はほとんどありませんが、初心者にとっては問題ありません。同じ式やおそらく他のものを含む複数の関数のサポートを追加しませんでした。それを試してみてください。

于 2009-05-06T13:48:49.843 に答える
0

ロバートが言ったように、正規表現が役立つでしょう。コマンドモードで、「/」文字に続けて正規表現を入力して、正規表現検索を開始します。

Ctags1も役立つかもしれません。プロジェクトのタグファイルを生成できます。このタグファイルを使用すると、「CTRL +]」を使用して別のファイルにある場合でも、ユーザーは関数呼び出しからその定義に直接ジャンプできます。

于 2009-05-06T13:51:26.797 に答える