문제

추출하려는 콘텐츠가 포함 된 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 실제로 원하는대로 (예 : 라인을 배열로 밀고 편집하고, 포맷하고, 무엇이든). 나는 next-실제로 가지고있는 줄을 지나서 START 또는 END, 그러나 당신은 그 행동을 원하지 않을 수도 있습니다. 보다 이 기사 이 연산자 및 기타 유용한 Perl 특수 변수에 대한 논의.

다른 팁

에서 perlfaq6대답 다른 라인에있는 두 패턴 사이에서 선을 꺼내려면 어떻게해야합니까?


Perl의 다소 이국적인 .. 연산자 (Perlop에 문서화)를 사용할 수 있습니다.

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

줄이 아닌 텍스트를 원한다면

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

그러나 시작을 통해 중첩 된 발생을 원한다면 균형 잡힌 텍스트 일치하는이 섹션의 질문에 설명 된 문제에 대해 반대 할 것입니다.

다음은 사용의 또 다른 예입니다. :

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

Perl에서 일치하는 라인 후 여러 줄을 잡으려면 어떻게해야합니까?

그게 어때? 그 중 하나에서 끝 문자열은 $^입니다. 끝 문자열로 변경할 수 있습니다.

나는 또한 초보자이지만, 그곳의 솔루션은 상당히 몇 가지 방법을 제공합니다 ... 위의 링크와 다른 것이 무엇인지 더 구체적으로 알려주십시오.

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

다음에 코드를 작성하십시오

Telemachus의 대답 이후, 상황이 쏟아지기 시작했습니다. 이것은 결국 내가보고있는 솔루션으로 작동합니다.

  1. 나는 두 줄로 구분 된 라인 (하나, "cinfile ="; 다른 줄은 단일 "#"을 포함하는 선이 별도의 라인을 포함하여 구분 기선을 제외하고 추출하려고합니다. 이것은 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 $_; }
    $found=1;
  } else { if($found == 1) { close($output); $counter++; $found=0; } }
}

나는 그것이 다른 사람들에게도 도움이되기를 바랍니다. 건배.

"가상 새로 온"에서 오는 것은 나쁘지 않습니다. 당신이 할 수있는 한 가지는 "$ found = 1"을 "if ($ found == 0) 블록 내부에 넣어 $ 시작과 $ 중지 사이에 매번 할당하지 않도록하는 것입니다.

내 생각에 약간 추악한 또 다른 것은 $ 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 $_;
            }
        }

    }
    # Find block of lines to extract                                                           

}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top