すべてのCコメントを別々のテキストファイルとして印刷する

すべてのCコメントを別々のテキストファイルとして印刷する

すべてのCコメントを別々のテキストファイルとして印刷したいと思います。

  • awk、sed、grep、またはbashを使用してください。
  • /* ... */(含む) の間にある複数行の C コメントをすべて出力します。
  • //コメントを含む出力ライン
  • オプション:行番号の印刷

この解決策を試しましたが、Ubuntuでは機能しません

私が要求した目的は、ソースコードのコメントを良い文書化の出発点としてすばやく使用できるようにすることです。私は専用のドキュメントプログラム(Doxygenなど)の複雑で排他的な組み込みコマンドが好きではありません。たとえば、各ソースコード関数に適切に注釈を付け、表面的なコメント行を削除すると、多くの時間が節約され、ほぼ完全な参照が提供されます。これはまた、より良いソースコードコメントを奨励するでしょう。

答え1

shell-magicを使用すると、すでに多くの答えがありますが、すでに持っているツールを使用すると簡単にできると思います。つまり、GCCです。

diff -u <(gcc -fpreprocessed -dD -E main.c) main.c | grep '^+' | cut -c 2-

どのように動作しますか?

  1. gcc -fpreprocessed -dD -E main.c ファイルからすべてのコメントを削除し、標準出力に入れます。

  2. diff -u <(...) main.c stdoutから入力を受け取り、元のデータと比較する

  3. grep '^+' で始まるすべての行をフィルタリングします+。つまり、以前に識別されたコメントをフィルタリングします。

  4. cut -c 2-+出力からシンボルを削除

非常に複雑な正規表現、Perl、または awk エントリは必要なく、他の回答で見逃した可能性があるすべての極端なケースも含まれます。

答え2

次の点を考慮すると、これは思ったほど簡単ではありません。 sがに表示されることを覚えてputs("string with /*")おいてください。"ch = '"'

または続けてください:

printf("...");    /\
* yes, this is a comment */
/\
/ and this as well

またはトライグラム

これらの問題を解決するために、我々は調整することができます反対の質問に対する答えですコメントを削除する代わりに印刷します。

perl -0777 -pe '
  s{
    (?<comment>
      # /* ... */ C comments
      / (?<lc> # line continuation
          (?<bs> # backslash in its regular or trigraph form
            \\ | \?\?/
          )
          (?: \n | \r\n?) # handling LF, CR and CRLF line delimiters
        )* \* .*? \* (?&lc)* /
      | / (?&lc)* / (?:(?&lc) | [^\r\n])* # // C++/C99 comments
    ) |
       "(?:(?&bs)(?&lc)*.|.)*?" # "strings" literals
       | '\''(?&lc)*(?:(?&bs)(?&lc)*(?:\?\?.|.))?(?:\?\?.|.)*?'\'' # (w)char literals
       | \?\?'\'' # trigraph form of ^
       | .[^'\''"/?]* # anything else
  }{$+{comment} eq "" ? "" : "$+{comment}\n"}exsg'

他の質問の人為的な例では、ほとんどのコーナーケースが扱われます。

#include <stdio.h>
int main()
{
  printf("%d %s %s %c%c%c%c%c %s %s %d\n",
  1-/* comment */-1,
  /\
* comment */
  "/* not a comment */",
  /* multiline
  comment */
  // comment
  /\
/ comment
  // multiline\
comment
  "// not a comment",
  '"' /* comment */ , '"',
  '\'','"'/* comment */,
  '\
\
"', /* comment */
  "\\
" /* not a comment */ ",
  "??/" /* not a comment */ ",
  '??''+'"' /* "comment" */);
  return 0;
}

以下を提供します。

/* comment */
/\
* comment */
/* multiline
  comment */
// comment
/\
/ comment
// multiline\
comment
/* comment */
/* comment */
/* comment */
/* "comment" */

行番号を取得するには、入力を一度に1行ずつ処理するのではなく、トピックがフル入力のフルルックサウンドモードで実行されているため、少しトリッキーです。(?{code})行区切り文字(Cでは、CR、LF、またはCRLF)が見つかるたびに、正規表現演算子を使用してカウンタをインクリメントすることでこれを実行できます。

perl -0777 -pe '
  s{
    (?<comment>(?{$l=$n+1})
      /
      (?<lc>  # line continuation
        (?<bs> # backslash in its regular or trigraph form
          \\ | \?\?/
        ) (?<nl>(?:\n|\r\n?) (?{$n++})) # handling LF, CR and CRLF line delimiters
      )*
      (?:
        \* (?: (?&nl) | .)*? \* (?&lc)* / # /* ... */ C comments
        | / (?:(?&lc) | [^\r\n])*         # // C++/C99 comments
      )
    ) |
       "(?:(?&bs)(?&lc)*.|.)*?" # "strings" literals
       | '\''(?&lc)*(?:(?&bs)(?&lc)*(?:\?\?.|.))?(?:\?\?.|.)*?'\'' # (w)char literals
       | \?\?'\'' # trigraph form of ^
       | (?&nl)
       | .[^'\''"/?\r\n]* # anything else
  }{$+{comment} eq "" ? "" : sprintf("%5d %s\n", $l, $+{comment})}exsg'

同じサンプルについて、次のように仮定します。

    5 /* comment */
    6 /\
* comment */
    9 /* multiline
  comment */
   11 // comment
   12 /\
/ comment
   14 // multiline\
comment
   17 /* comment */
   18 /* comment */
   21 /* comment */
   26 /* "comment" */

答え3

これはawk次のように実行できます。

#!/bin/awk

# Handles case where both /* and */ are on the same line
{ line_printed = 0; }

# Find the beginning of a multiline comment
/^[[:space:]]*\/\*/ {
    multiline = 1;

    # Remove leading spaces
    sub(/^[[:space:]]+/,"");
    printf "[%d] %s\n", NR, $0;
    line_printed = 1;
}

# Find the end of a multiline comment
/\*\/[[:space:]]*$/ {
    multiline = 0;
    if (line_printed == 0)
        printf "%s", $0;

    print "\n"
    next;
}

# The content between /* and */
{
    if ( multiline == 1 && line_printed == 0 )
    {
        print $0;
        next
    }
}

# A single line comment
/^[[:space:]]*\/\// {
    # Remove leading spaces
    sub(/^[[:space:]]+/,"");
    printf "[%d] %s\n\n", NR, $0;
}

このスクリプトを別のfoo.awk名前(または別の名前、拡張子はオプション)として保存してを使用してくださいawk -f foo.awk input.c。このスクリプトはすべてのコメント(追加の改行で区切られた)を印刷し、各コメントの前に行番号を追加します。

答え4

Update 2/15/24 - Raylibの使い方を学びながら、ソフトウェアスイートに含まれているC "パーサー"を見つけました。このソフトウェアは、私が必要としたことを正確に実行しているようです。以下を参照してください。https://github.com/raysan5/raylibすべての構造、定義、関数、コールバックなどを検索し、きれいに書式設定するという利点があります。

典型的な例

Function 232: DrawRectangleRounded() (4 input parameters)
  Name: DrawRectangleRounded
  Return type: void
  Description: Draw rectangle with rounded edges
  Param[1]: rec (type: Rectangle)
  Param[2]: roundness (type: float)
  Param[3]: segments (type: int)
  Param[4]: color (type: Color)

関連情報