Как я могу сохранить только первые пять строк в скаляре Perl? - PullRequest
4 голосов
/ 22 апреля 2009

В каком скаляре можно использовать регулярное выражение, чтобы сопоставить его первые пять строк и отбросить остальные?

Ответы [ 8 ]

9 голосов
/ 22 апреля 2009

Странный запрос, но для этого нужно:

#!/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;
6 голосов
/ 22 апреля 2009

Почему бы вам просто не использовать head для этого?

3 голосов
/ 22 апреля 2009

Вам не нужно регулярное выражение. Просто откройте дескриптор файла для ссылки на скаляр и сделайте те же действия, что и для любого другого дескриптора файла:

my $scalar = ...;

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

$scalar = join '', @lines;
2 голосов
/ 22 апреля 2009

Как говорит Брайан, вы можете довольно легко использовать head или tail для любой задачи (первые 5 строк или последние 5 строк).

Но теперь мне интересно, правильно ли я понимаю ваш вопрос. Когда вы говорите «для любого скаляра», подразумеваете ли вы, что (по какой-то причине) файл уже находится в скаляре?

Если нет, то я думаю, что лучшим решением является отсутствие регулярных выражений. Используйте $. и читайте файл в обычном или обратном направлении. Чтобы прочитать в обратном направлении, вы можете попробовать File::ReadBackwards или File::Bidirectional.

2 голосов
/ 22 апреля 2009
my ($first_five) = $s =~ /\A((?:.*\n){5})/;
my ($last_five) = $s =~ /((?:.*\n){5})\z/;
1 голос
/ 23 апреля 2009

Почему бы просто не использовать сплит с лимитом, он предназначен для этой цели:

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

Если вы хотите вернуть его как единый скаляр с пятью строками, присоедините его обратно:

my $scalar = join('\n', @lines) . "\n";
1 голос
/ 22 апреля 2009

Людям не хватает некоторых ключевых флагов:

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

Без многострочного флага он будет смотреть только на первую строку. Также, сделав опцию \n необязательной, мы можем взять первые пять строк , независимо от новой строки в конце пятого

0 голосов
/ 14 марта 2010
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]");
}
...