テキストブロックの抽出と比較

テキストブロックの抽出と比較

ブロックで構成されたファイルに集計されたデータがあります。

---- BLOCK ONE ----
some data
another data
more data
more data
-------------------

---- BLOCK two ----
some data
another data
-------------------

---- BLOCK THREE ----
some data
another data
more data
-------------------

など。総ブロック数は約2000個です。

項目(データ行)が4つ未満のブロックを抽出する必要があります。これを行う方法を知ってください(Perlが好ましいです)。

答え1

$ perl -00 -F'\n' -n -e '
  $file = shift @F;
  pop @F;
  if (@F < 4) {
    $file =~ s/^---- | ----//g;
    open(OUT, ">", $file.".txt");
    print OUT join("\n", @F), "\n"
  }' input.txt

-00このperl 1行ステートメントは、短絡モードで入力を読み込み(複数の改行で区切られている)、-F自動的に改行の入力を@ F配列に分割し、-n入力を印刷せずに自動的に読み取るために使用されます(に似ていますsed -n)。

まず、Shiftを使用して@Fの最初の要素を$ file変数に入れます。その後、pop @ Fは最後の要素(-------------------)を削除します。残りの要素が4つ未満の場合は、$ fileから合計を----削除し、書き込み用に----"$ file.txt"を開き、配列の残りの部分をそのファイルに印刷します。

これらのファイル名が気に入らない場合は、演算子を使用する$file = sprintf "file%04i.txt", ++$counter代わりにブロック内でカウンタ変数を増やすなど、他の方法を使用できます。ifs///

---- BLOCK...ただし、ヘッダーとフッターを維持するには、------*行をに置き換えてテストをに変更します。shiftpop$file = $F[0]ifif (@F < 6)

出力例(tailファイル名印刷用):

$ tail BLOCK*.txt
==> BLOCK THREE.txt <==
some data
another data
more data

==> BLOCK two.txt <==
some data
another data

スタンドアロンスクリプトと同じですが、カウンタを使用してファイル名を生成します。

$ cat split-blocks.pl
#!/usr/bin/perl

use strict;
my $counter;

$/='';

while(<<>>) {
  my @lines = split /\n/;
  my $file = shift @lines;
  pop @lines;

  if (@lines < 4) {
    $file = sprintf 'file%04i.txt', ++$counter
    open(OUT, ">", $file) || die "couldn't open $file for write: $!\n";
    print OUT join("\n", @lines), "\n"
  }
};

$ ./split-blocks.pl input.txt

$ tail file*
==> file0001.txt <==
some data
another data

==> file0002.txt <==
some data
another data
more data

答え2

これは簡単な一行です。

$ perl -00 -lne '@k=(/\n/mg); print if $#k < 4 ' file
---- BLOCK two ----
some data
another data
-------------------

---- BLOCK THREE ----
some data
another data
more data
-------------------

-00空白行で区切られた各行ブロックを単一の「行」として扱う短絡モードをオンにします。各呼び出しに-l改行を追加し、各入力「行」から末尾の改行を削除します。つまり、print各入力行で「-n次のスクリプトを実行します」を意味します。-e

スクリプト自体は、\n入力「行」(段落)から文字を見つけて配列に保存します。その後、配列の最大インデックスが4より小さい場合は、その行を印刷します。配列は最初から計算されることを忘れないでください。0これは最初の行も計算されるため、行が4つ未満の場合を意味しますが、最後の行は末尾の改行文字が削除されなかった-lため、配列の行数が4つ未満でブロックされました。

答え3

次のいずれかを使用してくださいawk

awk 'NF && !/^-/{ buf= buf (data?ORS:"") $0; data++ }
          /^-+$/{ if(data<4) { print (ors?ORS:"") buf; ors=ORS }; buf=data="" }' infile

出力:

some data
another data

some data
another data
more data

ブロックヘッダー/フッターを維持するには:

awk 'NF{ buf= buf (data?ORS:"") $0; data++ }
 /^-+$/{ if(data<=5) { print (ors?ORS:"") buf; ors=ORS }; buf=data="" }' infile

出力:

---- BLOCK two ----
some data
another data
-------------------

---- BLOCK THREE ----
some data
another data
more data
-------------------

答え4

perl -lne '
    if (/^-+$/) {
        print join "\n", @M, $_ if $#M < 4;
        @M = ();
        next;
    }

    if (/^-/) {
        $M[0] = $_;
        next;
    }

    push @M, $_ if $#M >= 0;
' file

自動印刷オプションが無効になっているため、perlファイルは1行ずつ読み取られます。perl(-n)

次に、セクションの内側にある場合は、その(push @M, $_ if $#M >= 0)行を配列にスライドさせます。

端部の内側にあり、(/^-+$/)配列の長さが4未満の場合は、印刷して配列を消去します(@M = ())

それ以外の場合は、セクションを開始し(/^-/)て現在の行を配列の最初の値として保存してからタイトルにします。


空の行を削除しましたが、必要に応じてそのままにしておくこともできます。

関連情報