1

我有一个带有重复行的大文件,如下所示:

@UUSM
ABCDEADARFA
+------qqq
!2wqeqs6777

我想输出文件中的所有“第二行”。为此,我截取了以下代码,但它没有按预期工作。相反,第 1、3 和 4 行在输出中。

open(IN,"<", "file1.txt") || die "cannot open input file:$!";
while (<IN>) {
$line = $line . $_;
if ($line =~ /^\@/) { 
    <IN>;
    #next;
    my $line = $line; 
    }
}
print "$line";

请帮忙!

4

4 回答 4

1
perl -ne '$at = $. if /^\@/; print if $. - 1 == $at' file1.txt

用手写体写出来,上面等价于

open my $fh, "<", "file1.txt";

my $at_line = 0;
while (<$fh>) {
    if (/^\@/) {
      $at_line = $.;
    }
    else {
      print if $. - 1 == $at_line;
    }
}
于 2013-08-31T18:12:49.493 回答
1

我假设您要问的是如何打印以以下开头的行之后的行@

perl -ne 'if (/^\@/) { print scalar <> }' file1.txt

这表示,“如果该行以 开头@,则打印下一行。对参数列表中的所有文件执行此操作。” 该scalar函数用于在文件句柄上施加标量上下文,因此它不会打印整个文件。默认情况print下,它的参数有一个列表上下文。

如果你真的想打印文件中的第二行,那会更容易。这里有几个例子:

使用行号$.变量,如果它等于行号 2,则打印。

perl -ne '$. == 2 and print, close ARGV' yourfile.txt

请注意,如果您有多个文件,则必须关闭 ARGV 文件句柄才能重置计数器$.。另请注意,使用较低优先级运算符and将强制printclose都绑定到条件。

使用常规逻辑。

perl -ne 'print scalar <>; close ARGV;'
perl -pe '$_ = <>; close ARGV;' 

这两个都通过在打印第二行时关闭 ARGV 文件句柄来使用短路功能。如果您想打印文件的每隔一行,如果您删除close语句,这两个都将执行此操作。

于 2013-08-31T18:28:43.983 回答
1

尝试这个

open(IN,"<", "file1.txt") || die "cannot open input file:$!";
my $lines = "";

while (<IN>) {
 if ($. % 4 == 2) $lines .= $_;
}

print "$lines";
于 2013-08-31T18:03:39.917 回答
0

如果要打印第 2、6、10 行,则:

while (<>)
{
    print if $. % 4 == 2;
}

当前行号在哪里$.——我没有花时间打开和关闭文件。那可能是:

{
    my $file = "file1.txt";
    open my $in, "<", $file or die "cannot open input file $file: $!";
    while (<$in>)
    {
        print if $. % 4 == 2;
    }
}

这使用了现代首选形式的文件句柄(词法文件句柄),结构周围的大括号表示文件句柄自动关闭。无法打开的文件名包含在错误消息中;使用了or运算符,因此优先级是正确的(括号和||原文中的也很好,可以在这里使用,但通常不是)。

如果您希望一行以 print 开头@,则必须以不同的方式组织事物。

my $print_next = 0;
while (<>)
{
    if ($print_next)
    {
        print $_;
        $print_next = 0;
    }
    elsif (m/^@/)
    {
        $print_next = 1;
    }
}

剖析问题中的代码

问题中代码的原始版本是(为方便起见添加了行号):

 1   open(IN,"<", "file1.txt") || die "cannot open input file:$!";
 2   while (<IN>) {
 3   $line = $line . $_;
 4   if ($line =~ /^\@/) {
 5       <IN>;
 6       #next;
 7       my $line = $line;
 8       }
 9   }
10   print "$line";

每一行的讨论:

  1. 好的,尽管它不使用词法文件句柄或报告无法打开的文件。
  2. 好的。
  3. 过早和误导。$line这会在任何分析完成之前将当前行添加到变量中。如果它是可取的,它可以写成$line .= $_;
  4. 建议所需输出的正确描述不是“第二行”而是“以@. 请注意,由于正则表达式上没有多行修饰符,因此它将始终仅匹配变量中的第一行段$line。由于过早连接,它将在每一行上匹配(因为第一行数据以 开头@),执行第 5-8 行中的代码。
  5. 将另一行读入$_. 它不测试 EOF,但这是无害的。
  6. 评论行;除了暗示一些混乱之外没有任何意义。
  7. my $line = $line;是对隐藏外部的新变量的自赋值$line……主要是,这很奇怪,在较小程度上它是无操作的。你没有使用use strict;use warnings;因为如果你这样做了,你会收到警告。Perl 专家使用use strict;anduse warnings;来确保他们没有犯愚蠢的错误;新手应该出于同样的原因使用它们。
  8. 就其本身而言,好的。但是,条件中的代码并没有真正做太多。它跳过文件中的第二行;它稍后会跳过第四,第六,第八等。
  9. 好的。
  10. 好的,但是...如果您只对打印行开始后的行@感兴趣,或者只对打印整数 N 的行号 2N+2 感兴趣,那么之前不需要在内存中构建整个字符串打印每一行。打印需要打印的每一行会更简单。
于 2013-08-31T17:59:48.577 回答