如何只在Perl标量中保留前五行?

时间:2009-04-22 10:31:24

标签: regex perl lines scalar

从任何类型的标量中,我可以使用什么样的正则表达式来匹配它的前五行并丢弃其余的?

8 个答案:

答案 0 :(得分:9)

奇怪的请求,但这应该这样做:

#!/usr/bin/perl

use strict;
use warnings;

my $s = join '', map { "$_\n" } 1 .. 9;

my ($first) = $s =~ /^((?:.*\n){0,5})/;
my ($last) = $s =~ /((?:.*\n){0,5})$/;


print "first:\n${first}last:\n$last";

更常见的解决方案是这样的:

#!/usr/bn/perl

use strict;
use warnings;

#fake a file for the example    
my $s = join '', map { "$_\n" } 1 .. 9;    
open my $fh, "<", \$s
    or die "could not open in memory file: $!";

my @first;
while (my $line = <$fh>) {
    push @first, $line;
    last if $. == 5;
}

#rewind the file just in case the file has fewer than 10 lines
seek $fh, 0, 0;

my @last;
while (my $line = <$fh>) {
    push @last, $line;
    #remove the earliest line if we have to many
    shift @last if @last == 6;
}

print "first:\n", @first, "last:\n", @last;

答案 1 :(得分:6)

为什么不直接使用head

答案 2 :(得分:3)

您不需要正则表达式。只需在对标量的引用上打开文件句柄,然后执行与任何其他类型的文件句柄相同的操作:

my $scalar = ...;

open my($fh), "<", \ $scalar or die "Could not open filehandle: $!";
foreach ( 1 .. 5 )
    {
    push @lines, scalar <$fh>;
    }
close $fh;

$scalar = join '', @lines;

答案 3 :(得分:2)

my ($first_five) = $s =~ /\A((?:.*\n){5})/;
my ($last_five) = $s =~ /((?:.*\n){5})\z/;

答案 4 :(得分:2)

正如布莱恩所说,你可以很容易地使用headtail来解决这两个问题(前5行或后5行)。

但现在我想知道我是否正确理解你的问题。当你说“对于任何类型的标量”时,你的意思是(无论出于何种原因)文件已经在标量中?

如果没有,我认为最好的解决方案是没有正则表达式。使用$.并正常或向后读取文件。要向后阅读,您可以尝试File::ReadBackwardsFile::Bidirectional

答案 5 :(得分:1)

人们缺少一些关键标志:

/(?m)((?:^.*\n?){1,5})/

没有多行标志,它只会看第一行。另外,通过使\n可选,我们可以使用前五个,而不管第五行末尾的换行符。

答案 6 :(得分:1)

为什么不直接使用split限制,它就是为此而设计的:

my @lines = (split /\n/, $scalar, 6)[0..4];

如果您希望将其作为具有五行的单个标量返回,请将其连接起来:

my $scalar = join('\n', @lines) . "\n";

答案 7 :(得分:0)

use strict;


my $line; #Store line currently being read
my $count=$ARGV[1]; # How many lines to read as passed from command line
my @last; #Array to store last count lines
my $index; #Index of the line being stored


#Open the file to read as supplied from command line
open (FILE,$ARGV[0]);
while ($line=<FILE>)
{
    $index=$.%$count;  # would help me in filter just $count records of the file
    $last[$index]=$line; #store this value
}
close (FILE);

#Output the stored lines
for (my $i=$index+1;$i<$count;$i++)
{
    print ("$last[$i]");
}
for (my $i=$0;$i<=$index;$i++)
{
    print ("$last[$i]");
}