Perlで2つの行区切り文字の間の行を抽出するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/1212799

質問

抽出したい内容のASCIIログファイルがあります。 Perlを適切に習得するのに時間がかかったことはありませんが、これはこのタスクに適したツールであると考えています。

ファイルは次のように構成されています:

... 
... some garbage 
... 
... garbage START
what i want is 
on different
lines 
END 
... 
... more garbage ...
next one START 
more stuff I want, again
spread 
through 
multiple lines 
END 
...
more garbage

だから、各 START END の区切り文字列の間の行を抽出する方法を探しています。 どうすればいいですか?

これまでのところ、 START 文字列を含む行を印刷する方法、または探しているものに多少関連するその他のドキュメント項目の例をいくつか見つけました。

役に立ちましたか?

解決

フリップフロップ演算子(範囲演算子と呼ばれる)が必要な場合 ..

#!/usr/bin/env perl
use strict;
use warnings;

while (<>) {
  if (/START/../END/) {
    next if /START/ || /END/;
    print;
  }
}

print の呼び出しを、実際にやりたいことで置き換えます(たとえば、行を配列にプッシュし、編集し、フォーマットします)。私は実際に START または END がある行を next -ingしていますが、その動作は望ましくないかもしれません。この演算子およびその他の説明については、この記事を参照してください。便利なPerl特殊変数。

他のヒント

perlfaq6 それ自体が異なる行にある2つのパターン間の行を引き出すにはどうすればよいですか


Perlのややエキゾチックな..演算子(perlopで文書化されています)を使用できます:

perl -ne 'print if /START/ .. /END/' file1 file2 ...

行ではなくテキストが必要な場合は、使用します

perl -0777 -ne 'print "$1\n" while /START(.*?)END/gs' file1 file2 ...

ただし、STARTからENDまでのネストされたオカレンスが必要な場合は、バランスの取れたテキストのマッチングに関するこのセクションの質問で説明されている問題に直面します。

.. :: pの別の使用例

while (<>) {
    $in_header =   1  .. /^$/;
    $in_body   = /^$/ .. eof;
# now choose between them
} continue {
    $. = 0 if eof;  # fix $.
}

複数を取得するにはどうすればよいですかPerlの一致する行の後の行?

それはどう?その1つでは、END文字列は$ ^です。これをEND文字列に変更できます。

私は初心者でもありますが、そこにある解決策は多くの方法を提供します...上記のリンクとは違うことをもっと具体的に教えてください。

while (<>) {
    chomp;      # strip record separator
    if(/END/) { $f=0;}
    if (/START/) {
        s/.*START//g;
        $f=1;
    }
    print <*>

次回はいくつかのコードを書いてみてください

."\n" if $f; }

次回はいくつかのコードを書いてみてください

Telemachusの返信後、物事が溢れ出しました。これは結局私が見ている解決策として機能します。

  1. 2つの文字列で区切られた行を抽出しようとしています行。これはTelemachusのソリューションでできます。
  2. 最初の行には削除したいスペースがあります。私も含めています。
  3. また、各行セットを個別のファイルに抽出しようとしています。

これは私にとってはうまくいきますが、コードはいものに分類できます。これは、私が現在、Perlの事実上の新人だからです。とにかくここに行きます:

#!/usr/bin/env perl
use strict;
use warnings;

my $start='CINFILE=

他の人にも役立つことを願っています。 乾杯。

; my $stop='^#

他の人にも役立つことを願っています。 乾杯。

; my $filename; my $output; my $counter=1; my $found=0; while (<>) { if (/$start/../$stop/) { $filename=sprintf("boletim_%06d.log",$counter); open($output,'>>'.$filename) or die $!; next if /$start/ || /$stop/; if($found == 0) { print $output (split(/ /))[1]; } else { print $output

Telemachusの返信後、物事が溢れ出しました。これは結局私が見ている解決策として機能します。

  1. 2つの文字列で区切られた行を抽出しようとしています行。これはTelemachusのソリューションでできます。
  2. 最初の行には削除したいスペースがあります。私も含めています。
  3. また、各行セットを個別のファイルに抽出しようとしています。

これは私にとってはうまくいきますが、コードはいものに分類できます。これは、私が現在、Perlの事実上の新人だからです。とにかくここに行きます:

<*>

他の人にも役立つことを願っています。 乾杯。

; } $found=1; } else { if($found == 1) { close($output); $counter++; $found=0; } } }

他の人にも役立つことを願っています。 乾杯。

「仮想の新人」から来るのは悪くない。できることの1つは、&quot; $ found = 1&quot; &quot; if($ found == 0)&quot;の内側$ startと$ stopの間で毎回その割り当てを行わないようにブロックします。

もう少しaいのは、私の意見では、$ start / $ stop-blockを入力するたびに同じファイルハンドラを開くことです。

これはそれを回避する方法を示しています:

#!/usr/bin/perl

use strict;
use warnings;

my $start='CINFILE=;
my $stop='^#;
my $filename;
my $output;
my $counter=1;
my $found=0;

while (<>) {

    # Find block of lines to extract                                                           
    if( /$start/../$stop/ ) {

        # Start of block                                                                       
        if( /$start/ ) {
            $filename=sprintf("boletim_%06d.log",$counter);
            open($output,'>>'.$filename) or die $!;
        }
        # End of block                                                                         
        elsif ( /$end/ ) {
            close($output);
            $counter++;
            $found = 0;
        }
        # Middle of block                                                                      
        else{
            if($found == 0) {
                print $output (split(/ /))[1];
                $found=1;
            }
            else {
                print $output 

「仮想の新人」から来るのは悪くない。できることの1つは、&quot; $ found = 1&quot; &quot; if($ found == 0)&quot;の内側$ startと$ stopの間で毎回その割り当てを行わないようにブロックします。

もう少しaいのは、私の意見では、$ start / $ stop-blockを入力するたびに同じファイルハンドラを開くことです。

これはそれを回避する方法を示しています:

<*>; } } } # Find block of lines to extract }
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top