2

我将总行数作为用户输入,然后从文件中删除这些行数。

我看到了这个 learn.perl.org/faq/perlfaq5.html#How-do-I-count-the-number-of-lines-in-a-file- 然后我厌倦了下面的简单逻辑。

逻辑:

  1. 获取总行数
  2. 减去用户输入的数字
  3. 打印线条

这是我的代码:

#!/usr/bin/perl -w
use strict;

open IN, "<", "Delete_line.txt"
    or die " Can not open the file $!";
open OUT, ">", "Update_delete_line.txt" 
    or die "Can not write in the file $!";

my ($total_line, $line, $number, $printed_line);

print"Enter the number of line to be delete\n";
$number = <STDIN>;

while ($line = <IN>) {

    $total_line = $.;  # Total number of line in the file
}

$printed_line = $total_line - $number;

while ($line = <IN>) {

    print OUT $line unless $.== $printed_line;      
}

好吧,我既没有收到任何代码错误,也没有任何输出?为什么我只是不知道。

任何人都可以给我一些建议。

4

10 回答 10

12

对大文件有效的 Perl 解决方案需要使用File::ReadBackwards

use File::ReadBackwards qw( );

my $num_lines = 10;
my $qfn = 'file.txt';

my $pos = do {
   my $fh = File::ReadBackwards->new($qfn)
      or die $!;
   $fh->readline() for 1..$num_lines;
   $fh->tell()
};

truncate($qfn, $pos)
   or die $!;
  • 这不会两次读取整个文件(与 OP 的方法不同)。
  • 这不会读取整个文件(与Tie::File解决方案不同)。
  • 这不会将整个文件读入内存。
于 2012-10-02T19:51:27.773 回答
6

另一种方法是使用Tie::File

#!/usr/bin/env perl
use strict;
use warnings;
use Tie::File;
tie my @lines, 'Tie::File', 'myfile' or die "$!\n";
$#lines -= 10;
untie @lines;

这样做的好处是在执行操作时不会将文件加载到内存中。

于 2012-10-02T19:20:28.597 回答
4

这是一个通过流并打印除最后n行之外的所有行的解决方案,其中n是命令行参数:

#!/usr/bin/perl

my @cache;
my $n = shift @ARGV;

while(<>) {
    push @cache, $_;
    print shift @cache if @cache > $n;
}

或单行版本:

perl -ne'BEGIN{$n=shift@ARGV}push@c,$_;print shift@c if@c>$n' NUMBER
于 2012-10-02T20:00:20.940 回答
2

从 IN 读完后,您必须重新打开它或seek IN, 0, 0重置它的位置。您还必须$.再次设置为零。

此外,最终条件应更改为,unless $. > $printed_line以便您跳过所有超过阈值的行。

于 2012-10-02T19:07:38.460 回答
1

“更有趣”的答案:使用Tie::File

use strict;
use warnings;

use Tie::File;
tie my @file, 'Tie::File', 'filename' or die "$!";

$#file -= 10;
于 2012-10-02T19:21:44.773 回答
1

您可以只缓冲最后 10 行,然后不打印剩余的 10 行。

use English qw<$INPLACE_EDIT>;

{   local @ARGV         = $name_of_file_to_edit;
    local $INPLACE_EDIT = '.bak';
    my @buffer;
    for ( 1..$num_lines_to_trim ) { 
        push @buffer, <>;
    }

    while ( <> ) { 
        print shift @buffer;
        push @buffer, $_;
    }
}

你也可以这样做File::Slurp::edit_file_lines

my @buffer;
my $limit_reached = 0;
edit_file_lines {  
    push @buffer, $_;
    return ( $limit_reached ||= @buffer > $num_lines_to_trim ) ? shift @buffer
         :                                                       ''
         ;
} $name_of_file;
于 2012-10-02T19:53:41.353 回答
1

只需反向读取文件并删除前 n 行:-

open my $filehandle, "<", "info.txt";
my @file = <$filehandle>;
splice(@file, -10);
print @file;

注意:这会将整个文件加载到内存中。

于 2012-10-02T19:11:20.727 回答
0
my $num_lines = 10;
my $qfn       = 'file.txt';

system('head', '-n', -$num_lines, '--', $qfn);
die "Error" if $?;
于 2012-10-02T19:15:06.730 回答
0

使用 C 很容易for

#!/usr/bin/perl -w
use strict;

open(my $in,"<","Delete_line.txt") or die "Can not open the file $!";
open(my $out,">","Update_delete_line.txt") or die"Can not write in the file $!";

print"Enter the number of lines to be delete\n";
my $number=<STDIN>;

my @file = <$in>;

for (my $i = 0; $i < $#file - $number + 1; $i++) {
    print $out $file[$i];
}

close $in;
close $out;
于 2012-10-02T19:11:07.783 回答
0
  #
  # Reads a file trims the top and the bottom of by passed num of lines
  # and return the string 
  # stolen from : http://stackoverflow.com/a/9330343/65706
  # usage :       
  # my $StrCatFile = $objFileHandler->ReadFileReturnTrimmedStrAtTopBottom ( 
  #       $FileToCat , $NumOfRowsToRemoveAtTop , $NumOfRowsToRemoveAtBottom) ; 
  sub ReadFileReturnTrimmedStrAtTopBottom {

     my $self = shift ; 
     my $file = shift ; 
     my $NumOfLinesToRemoveAtTop = shift ; 
     my $NumOfLinesToRemoveAtBottom = shift ; 

     my @cache ; 
     my $StrTmp = () ; 
     my $StrReturn = () ; 
     my $fh = () ; 

     open($fh, "<", "$file") or cluck (   "can't open file : $file for reading: $!" ) ;
     my $counter = 0;
     while (<$fh>) {
         if ($. >= $NumOfLinesToRemoveAtTop + 1) {
             $StrTmp .= $_ ;
         }
     } 
     close $fh;

     my $sh = () ; 
     open( $sh, "<", \$StrTmp) or cluck(   "can't open string : $StrTmp for reading: $!" ) ;
     while(<$sh>) {
         push ( @cache, $_  ) ;
         $StrReturn .= shift @cache if @cache > $NumOfLinesToRemoveAtBottom;
     }
     close $sh ; 
     return $StrReturn ; 
  } 
  #eof ReadFileReturnTrimmedStrAtTopBottom
  #
于 2012-10-28T17:19:28.817 回答