Если строка для поиска одинакова, пусть Perl выполнит обработку , используя поисковую фразу в качестве разделителя входных записей :
open my $fh, '<', 'test.dat' or die "can't open $!"; # usual way of opening a file
my @list; # declare empty array 'list' (results)
$/= 'add this word to the list:'; # define custom input record seperator
while( <$fh> ) { # read records one by one
push @list, $1 if /(\S\S*)/
}
close $fh; # thats it, close file!
print join "\n", @list; # this will list the results
выше "почти нормально", оно сохранит первое слово файла в $ list [0] из-за способа обработки.Но этот способ позволяет очень легко понять (imho)
blah <== first word of the file
1234.56
PINAPPLE
1!@#$%^&*()[]{};:'",<.>/?asdf
Q : почему бы просто не просмотреть строки с одним регулярным выражением по всем данным (как уже было предложено здесь).Потому что, по моему опыту, обработка записей с регулярным выражением для каждой записи (вероятно, очень сложное регулярное выражение в реальном случае) будет быстрее - особенно для очень больших файлов.Вот причина.
Тест в реальном мире
Чтобы подтвердить это утверждение, я провел несколько тестов с файлом данных объемом 200 МБ, содержащим 10000 ваших маркеров.Источник теста следующий:
use strict;
use warnings;
use Benchmark qw(timethese cmpthese);
use FILE::Slurp;
# 'data.dat', a 200MB data file, containing 10_000
# markers: 'add this word to the list:' and a
# one of different data items after each.
my $t = timethese(10,
{
'readline+regex' => sub { # trivial reading line-by-line
open my $fh, '<', 'data.dat' or die "can't open $!";
my @list;
while(<$fh>) {
push @list,$1 if /add this word to the list:\s*(\S+)/
}
close $fh;
return scalar @list;
},
'readIRS+regex' => sub { # treat each 'marker' as start of an input record
open my $fh, '<', 'data.dat' or die "can't open $!";
$/= 'add this word to the list:'; # new IRS
my @list;
while(<$fh>) { push @list, $1 if /(\S+)/ }
close $fh;
return scalar @list;
},
'slurp+regex' => sub { # read the whole file and apply regular expression
my $filecontents = File::Slurp::read_file('data.dat');
my @list = $filecontents =~ /add this word to the list:\s*(\S+)/g;
return scalar @list;
},
}
);
cmpthese( $t ) ;
, который выводит следующие результаты синхронизации:
Benchmark: timing 10 iterations of readIRS+regex, readline+regex, slurp+regex...
readIRS+regex: 43 wallclock secs (37.11 usr + 5.48 sys = 42.59 CPU) @ 0.23/s (n=10)
readline+regex: 42 wallclock secs (36.47 usr + 5.49 sys = 41.96 CPU) @ 0.24/s (n=10)
slurp+regex: 142 wallclock secs (135.85 usr + 4.98 sys = 140.82 CPU) @ 0.07/s (n=10)
s/iter slurp+regex readIRS+regex readline+regex
slurp+regex 14.1 -- -70% -70%
readIRS+regex 4.26 231% -- -1%
readline+regex 4.20 236% 1% --
, что в основном означает, что простое считывание строк и блочное считывание с помощью пользовательских IRSпримерно в 2,3 раза быстрее (один проход за ~ 4 с), чем выкачивать файл и сканировать с помощью регулярного выражения.
В основном это говорит о том, что если вы обрабатываете файлы такого размера в такой системе, как моя ;-)Вы должны читать построчно , если ваша проблема поиска находится в одной строке , и читать с помощью пользовательского разделителя входных записей , если ваша проблема поиска включает более одной строки (мои 0,02 доллара США).
Хотите тоже сделать тест?Вот этот:
use strict;
use warnings;
sub getsomerandomtext {
my ($s, $n) = ('', (shift));
while($n --> 0) {
$s .= chr( rand(80) + 30 );
$s .= "\n" if rand($n) < $n/10
}
$s x 10
}
my @stuff = (
q{1234.56}, q{PINEAPPLE}, q{1!@#$%^&*()[]{};:'",<.>/?asdf}
);
my $fn = 'data.dat';
open my $fh, '>', $fn or die $!;
my $phrase='add this word to the list:';
my $x = 10000;
while($x --> 0) {
print $fh
getsomerandomtext(1000), ' ',
$phrase, ' ', $stuff[int(rand(@stuff))], ' ',
getsomerandomtext(1000), "\n",
}
close $fh;
print "done.\n";
создает 200 МБ входного файла 'data.dat'.
С уважением
rbo