임계값보다 작은 숫자로 가장 긴 일련의 줄을 인쇄하는 방법은 무엇입니까?

임계값보다 작은 숫자로 가장 긴 일련의 줄을 인쇄하는 방법은 무엇입니까?

저는 Perl을 배우고 있지만 이 문제를 해결하는 방법을 모르겠습니다.

.txt다음 형식의 파일이 있습니다 .

1 16.3346384
2 11.43483
3 1.19819
4 1.1113829
5 1.0953443
6 1.9458343
7 1.345645
8 1.3847385794
9 1.3534344
10 2.1117454
11 1.17465
12 1.4587485

첫 번째 열에는 줄 번호만 포함되어 있으며 여기서는 관심이 없지만 두 번째 열의 값은 관련 부분입니다.

두 번째 열에 2.00보다 작은 숫자를 가진 가장 긴 연속 행 시퀀스를 출력하고 싶습니다. 위의 예에서는 3~9행이 되며 출력은 다음과 같아야 합니다.

1.19819
1.1113829
1.0953443
1.9458343
1.345645
1.3847385794
1.3534344

답변1

펄 한 줄:

perl -ne '$n = (split)[1]; if ($n > 2) {if ($i > $max) {$longest=$cur; $cur=""; $max=$i}; $i=0} else {$cur .= $n . "\n"; $i++} END {print $i > $max ? $cur : $longest}' < file.txt

더 나은 가독성을 위한 여러 줄:

perl -ne '
  $n = (split)[1];
  if ($n > 2) {
    if ($i > $max) {
      $longest=$cur;
      $cur="";
      $max=$i;
     }
     $i=0
  } else {
    $cur.= $n . "\n";
    $i++
  } 
  END {
    print $i > $max ? $cur : $longest
  }' < file.txt

라이너 1개 awk:

awk '$2 > 2 { if (i > max) {res=cur; cur=""; max=i} i=0} $2 < 2 {cur = cur $2 "\n"; i++} END {if (i > max) res=cur; printf res}' file.txt

여러 줄:

awk '
  $2 > 2 { 
    if (i > max) {
      res=cur
      cur=""
      max=i
    }
    i=0
  } 
  $2 < 2 {
    cur = cur $2 "\n"
    i++
  }
  END {
    if (i > max) res=cur
    printf res
  }' file.txt

답변2

이것은 결코 사소한 일이 아닙니다. 완성된 프로그램을 제공하는 것이 다른 사람들이 프로그래밍 언어의 문제 해결 방법을 배우는 데 도움이 되는지에 대한 논쟁도 있지만, 나는 그것이 장점이 있다고 믿기 때문에 다음 프로그램을 제안합니다(이름 findlongestsequence.pl:

#!/usr/bin/perl
use strict;
use Getopt::Long;

my $limit; my $infile;
GetOptions( 'limit=f' => \$limit, 'infile=s' => \$infile );

my $lineno=0; my $groupstart;
my $currlength=0; my $maxlength=0; my $ingroup=0;
my @columns; my @groupbuf; my @longestgroup;

if (! open(fileinput, '<', "$infile" )) {exit 1;};
while (<fileinput>)
{
    $lineno++;
    @columns = split(/\s+/,$_);

    if ( $ingroup == 0 && $columns[1]<$limit )
    {
        $ingroup=1;
        $groupstart=$lineno;
        @groupbuf=();
    }

    if ( $ingroup == 1 )
    {
        if ($columns[1]>=$limit )
        {
            $ingroup=0;
            $currlength=$lineno-$groupstart;
    
            if ( $currlength>$maxlength )
            {
                $maxlength=$currlength;
                @longestgroup=@groupbuf;
            }
        }
        else
        {
            push(@groupbuf,$columns[1]);
        }
    }
}
close(fileinput);

if ( $ingroup == 1 )
{
    $currlength=$groupstart-$lineno;
    if ( $currlength>$maxlength )
    {
        $maxlength=$currlength;
        @longestgroup=@groupbuf;
    }
}

print join("\n",@longestgroup),"\n";
exit 0;

이 프로그램을 호출할 수 있습니다.

./findlongestsequence.pl --infile input.txt --limit 2.0

먼저 해석된 명령줄 인수를 사용합니다 Getopt::Long.

그런 다음 파일을 열고 한 줄씩 읽습니다 $lineno. 각 줄은 공백이 있는 열로 분할됩니다.

  • $limit프로그램이 값이 < ( 0) 인 행 그룹에 없지만 $ingroup적절한 행을 발견하면 현재 해당 그룹( $ingroup1로 설정)에 있음을 기록하고 그룹 시작 $groupstart및 시작 버퍼링 열을 저장합니다. 2개의 배열 값입니다 @groupbuf.
  • 프로그램이 그러한 그룹 내에 있지만 현재 값이 보다 큰 경우 $limit그룹 꼬리를 식별하고 길이를 계산합니다. 이전에 기록된 가장 긴 그룹보다 긴 경우 새로운 가장 긴 그룹의 내용( @groupbuf)과 길이( )가 각각 및 에 복사됩니다 .$currlength@longestgroup$maxlength

그룹은 > 값이 있는 줄이 아닌 파일 끝에서 종료될 수 있으므로 이 검사는 파일 끝에서 true인 경우 $limit에도 수행됩니다 .$ingroup

마지막으로 @longestgroup인쇄된 내용은 \n토큰 구분 기호 역할을 합니다.

답변3

awk를 사용하십시오.

$ cat tst.awk
$2 >= 2 {
    max = getMax(cur,max)
    cur = ""
    next
}
{ cur = cur $2 ORS }
END {
    printf "%s", getMax(cur,max)
}
function getMax(a,b) {
    return ( gsub(ORS,"&",a) > gsub(ORS,"&",b) ? a : b )
}

$ awk -f tst.awk file
1.19819
1.1113829
1.0953443
1.9458343
1.345645
1.3847385794
1.3534344

답변4

<>읽기 입력 및 트리거 연산자를 위한 관용적인 솔루션입니다.

#!/usr/bin/env perl
use strict;
use warnings;
# https://unix.stackexchange.com/questions/766081/how-to-print-the-longest-sequence-of-lines-featuring-numbers-smaller-than-a-thre
my $threshold = 2.00;
my ($section, $maxsection, $len, $maxlen);
my $flipflop;
while (<>) {
    # Remove leading line number
    s/^(\d+)\s+//;
    # Flip flop operator
    # https://www.effectiveperlprogramming.com/2010/11/make-exclusive-flip-flop-operators/
    if ($flipflop = $_ <= $threshold .. $_ > $threshold) {
        if ($flipflop =~ /E0$/) {
            # End of section
            if (!defined($maxlen) || $len > $maxlen) {
                $maxsection = $section;
                $maxlen = $len;
            }
            $len = 0;
            $section = "";
        } else {
            $len++;
            $section .= $_;
        }
    }
}
# One last possible end of section
if ($flipflop && $len > $maxlen) {
    $maxsection = $section;
}
print $maxsection;

관련 정보