Perlなどのツールを使用した複数行の編集

Perlなどのツールを使用した複数行の編集

.uncrustify.cfg読みやすくするためにファイルを編集しています。次のように再フォーマットしたいと思います。

2行:

# Add or remove between the parens in the function type: 'void (*x)(...)'
sp_after_tparen_close      = ignore   # ignore/add/remove/force

1行出力:

sp_after_tparen_close      = ignore   # ignore/add/remove/force#   Add or remove between the parens in the function type: 'void (*x)(...)'

Perlが最良の選択だったようですが、構文に圧倒されました。 10年の余裕があれば学びます ;-)

もっと一般化するには、次のようにします。

2行:

#a comment line
some code

1行出力:

some code # a comment line

==========================

John:手描きの2行:

nl_while_brace             = ignore   # I,A,R,F     # Add or remove newline between 'while' and '{'
nl_scope_brace             = ignore   # I,A,R,F     # Add or remove newline between 'scope (x)' and '{' (D)

...awkを使用せずに2つのペアを組み合わせました。

# Add or remove newline between 'unittest' and '{' (D)
nl_unittest_brace          = ignore   # I,A,R,F

# Add or remove newline between 'version (x)' and '{' (D)
nl_version_brace           = ignore   # I,A,R,F

答え1

sed '/^#/N;s/\(.*\)\n\([^#].*\)/\2 \1/;P;D'

これは質問の簡単な例を扱います。コメントではなく、少なくとも1つの文字を含む行が続くすべてのコメント行は、その後の行に追加されます。

したがって、例を実行すると、出力は次のようになります。

sp_after_tparen_close      = ignore   # ignore/add/remove/force # Add or remove between the parens in the function type: 'void (*x)(...)'

@John1024の例を実行すると、出力は次のようになります。

#
# Some comments
#

sp_after_tparen_close      = ignore   # ignore/add/remove/force # Add or remove between the parens in the function type: 'void (*x)(...)'

some code #a comment line
more code

# comment one
# comment two
still more code # comment three

これらのケースを処理するためにsedループは必要ありません。この場合、\newline文字を含めることができる唯一の行は、ハッシュで始まる行です。なぜなら、この行に 1 が追加される#唯一の行だからです。sed

sedハッシュで始まる行に出会ったら、追加の入力行を取得#してNパターン空間に追加します。sed次に、次のs///ものを交換してみてください。

  • \(.*\)- できるだけ多くの引用を使用し、\1その後に...
  • \n- 改行文字が続きます...
  • \([^#].*\)- ハッシュ以外の文字が1つ以上あり、#パターン空間にすべてが残っています。
  • そして\2 \1

sed次に、P最初に表示される\newline文字までパターンスペースを印刷し、D同じ文字を削除して残りを再試行します。(そうであれば)

答え2

私はこれがあなたが望むことをすると信じています:

awk '/^[[:space:]]*[^#]/ && last ~ /^#/ {printf "%s %s",$0,last; last="";next} {print last; last=$0} END{print last}' sample.cfg

たとえば、次の入力ファイルがあるとします。

#
# Some comments
#

# Add or remove between the parens in the function type: 'void (*x)(...)'
sp_after_tparen_close      = ignore   # ignore/add/remove/force

#a comment line
some code
more code

# comment one
# comment two
# comment three
still more code

出力は次のとおりです

$ awk '/^[[:space:]]*[^#]/ && last ~ /^#/ {printf "%s %s",$0,last; last="";next} {print last; last=$0} END{print last}' uncrustify.cfg

#
# Some comments
#

sp_after_tparen_close      = ignore   # ignore/add/remove/force # Add or remove between the parens in the function type: 'void (*x)(...)'

some code #a comment line
more code

# comment one
# comment two
still more code # comment three

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

awkファイルの各行を暗黙的に繰り返します。

lastこのスクリプトは、前の行を保持する単一の変数を使用します。簡単に言えば、各行を繰り返しながら、最後の行がコメントであり、現在の行がコメントでない場合は、2行を一緒に印刷します。それ以外の場合は、最後の行を印刷します。

  • /^[[:space:]]*[^#]/ && last ~ /^#/ {printf "%s %s",$0,last; last="";next}

    (a)この行がコメントではなく(b)前(最後)の行がコメントの場合、最後の行と現在の行が結合されて印刷されます。それ以降はlastクリア可能です。その後、残りのコマンドをスキップしてジャンプして再起動しますnext

  • {print last; last=$0}

    それ以外の場合は、そのlast行を印刷します。last現在行の内容で更新されます。

  • END{print last}

    ファイル内のすべての行を繰り返してから、そのlast行の内容を印刷します。

他の例

次の入力を考慮してください。

# Add or remove newline between 'unittest' and '{' (D)
nl_unittest_brace          = ignore   # I,A,R,F

# Add or remove newline between 'version (x)' and '{' (D)
nl_version_brace           = ignore   # I,A,R,F

出力は次のとおりです

$ awk '/^[[:space:]]*[^#]/ && last ~ /^#/ {printf "%s %s",$0,last; last="";next} {print last; last=$0} END{print last}' new

nl_unittest_brace          = ignore   # I,A,R,F # Add or remove newline between 'unittest' and '{' (D)

nl_version_brace           = ignore   # I,A,R,F # Add or remove newline between 'version (x)' and '{' (D)

答え3

私の意見によれば、コマンドラインを操作するよりも短いスクリプトでこのようなものを開発するのが最も簡単です。さらに、保管することもできます。

#!/usr/bin/perl
use strict;
use warnings FATAL => qw(all);

my $buffer = "";
my $linesBuffered = 0;

while (<STDIN>) {
# Check if this line is a just a comment.
    if ($_ =~ /^\s*#/) {
    # Assume multi-line comments should not be appended.
        if ($buffer) { $buffer .= $_ }
        else { $buffer = $_ }
        $linesBuffered++;
    } else {
        if ($linesBuffered > 1) {
        # Print multi-line comment.
            print "$buffer$_";
        # Reset buffer.
            $buffer = "";
            $linesBuffered = 0;
        } elsif ($buffer) {
        # Print buffered line with comment trailing.
            chomp $_;
            print "$_ $buffer";
        # Reset buffer.
            $buffer = "";
            $linesBuffered = 0;
        } else { print $_ }
    }
}

print $buffer if ($buffer);  

たとえば、これを使用できます./filter.pl < .uncrustify.cfg > .uncrustify.copy。これはまだ完了していないので、cp .uncrustify.copy .uncrustify.cfg満足している場合は後で行う必要があります。標準入力から読み取るのでテストできます。

> ./filter.pl
what  <- stdin
what  <- stdout

ここではコメントではないので、すぐにその行を吐き出します。次の例では、stdinとstdoutを指摘しません。

#okay
then
then #okay

この場合、コメント行をバッファリングして次の(コメントではなく)行に追加します。

#foo
#bar
#foo
#bar

この場合、複数行のコメントを出力します。

今数時間:

  • Perlでは、空の文字列("")がfalseをテストします。
  • /^\s*#/0個以上のスペースで始まり、後ろに#
  • edでない限りchomp、入力行の末尾に改行文字があるはずです。

以下はJohn1024の例の出力です。

#
# Some comments
#

sp_after_tparen_close      = ignore   # ignore/add/remove/force # Add or remove between the parens in the function type: 'void (*x)(...)'

some code #a comment line
more code

# comment one
# comment two
# comment three
still more code

どこに注目してください# comment threeこれはJohn1024とmikeservの出力に関連しています。これは意図的ですが、その値は要件によって異なります。ここで私が好むのは、次のコード行の前に複数行コメントの最後の行を追加してはいけないと仮定することです。一つの線コードの後ろにあるコメントが移動されました。これを行うと、スクリプトがより複雑になります。それ以外の場合、変数$linesBufferedと関連ロジックは必要ありません。

関連情報