我正在学习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 一行:
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
($ingroup
为零)的行中,但遇到合适的行,它将记录它现在在这样的组中($ingroup
设置为1),存储组开始$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;