2009-04-22 4 views

ответ

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; 
+0

как бы применить это к последним 5 строкам? – Tanami

+0

my ($ last_five_lines) = $ s = ~ /((?:.*\n){5})\z/; –

+0

Вам нужен модификатор {0,5}, иначе он отклонит строку из 4 строк (если это не то, что вы хотите). –

6

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

+0

Если большая строка находится внутри программа Perl, и вы не хотите создавать временные файлы, вы не можете этого сделать. –

+0

@brian d foy Хм, неправда, вы можете открыть двунаправленную трубу на голову; это было бы глупо, но вы можете это сделать. –

+1

Вы можете открыть двунаправленную трубку? Вы знаете, Perl работает во многих местах. :) –

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

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

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

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

+0

Файл :: ReadBackwards хорош, если файл очень длинный. –

1

Люди отсутствуют некоторые ключевые флаги:

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

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

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; 
+0

Брайан - это опечатка, где вы ссылаетесь на $ fh дважды в вызове open()? – Alnitak

1

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

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

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

my $scalar = join('\n', @lines) . "\n"; 
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]"); 
} 
Смежные вопросы