Как я могу отсортировать список строк по номерам в них?
легкий, без сомнения, для вас...
у меня есть список имен, которые похожи на это;
fw_d.log.1.gz
through
fw_d.log.300.gz
когда я использую этот код ниже блока, это почти все так, как я хочу, но не совсем.
#!/usr/bin/perl -w
my $basedir = "/var/log";
my @verdir = qw(fw_d);
my $fulldir;
my $configs;
my $combidir;
foreach $combidir (@verdir) {
$fulldir = "$basedir/$combidir";
opendir (DIR, $fulldir);
my @files = grep { $_ ne '.' && $_ ne '..' && $_ ne 'CVS' readdir DIR;
closedir (DIR);
@files1 = sort {$a cmp $b}(@files);
foreach my $configs (@files1) {
print "Checking $configsn";
system("less $basedir/$combidir/$configs | grep '.* Group = , Username = .* autheauthenticated.' >> output.log" );
}
}
вот фрагмент вывода
Checking fw_d.log
Checking fw_d.log.1.gz
Checking fw_d.log.10.gz
Checking fw_d.log.100.gz
Checking fw_d.log.101.gz
Checking fw_d.log.102.gz
как вы можете видеть, это почти все, как я надеялся.... У кого-нибудь есть предложения по чтению или фрагменту кода, который я могу использовать?
спасибо заранее.
Стив.
4 ответов
можно использовать Schartzian-преобразования :
my @sorted = map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [$_, $_=~/(\d+)/] }
@files;
print Dumper \@sorted;
добавлен бенчмарк для сравнения между преобразованием Шварца и подпрограммой
use Benchmark qw(:all);
# build list of files
my @files = map {'fw_d.log.'.int(rand()*1000).'.log' } 0 ..300;
my $count = -3;
my $r = cmpthese($count, {
'subname' => sub {
sub expand {
my $file=shift;
$file=~s{(\d+)}{sprintf "%04d", }eg;
return $file;
}
my @sorted = sort { expand($a) cmp expand($b) } @files;
},
'schwartzian' => sub {
my @sorted = map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [$_, $_=~/(\d+)/] }
@files;
}
});
результат:
Rate subname schwartzian
subname 21.2/s -- -92%
schwartzian 279/s 1215% --
преобразование Шварца примерно в 13 раз эффективнее для сортировки 300 файлов.
проблема в том, что код делает то, что вы ему говорите: сортируйте имена файлов в алфавитном порядке.
вы должны заменить sort { $a cmp $b }
by sort { expand($a) cmp expand($b) }
С expand
:
sub expand
{ my $file=shift;
$file=~s{(\d+)}{sprintf "%04d", }eg; # expand all numbers to 4 digits
return $file;
}
вы можете попробовать использовать пользовательскую функцию сортировки:
sub sort_by_number {
$a =~ /(\d+)/;
$numa = ;
$b =~ /(\d+)/;
$numb = ;
return $numa <=> $numb;
}
а затем отсортировать следующим образом:
@files1 = sort sort_by_number @files;
это будет сортировать строки в @files
значение первого числа в каждой строке.
более старый вопрос, но есть ответ, пока не упомянутый.
Sort::Naturally
делает это для вас:
сортировка лексически, но сортировка числительных частей числительно
#!/usr/bin/env perl
use strict;
use warnings;
use Sort::Naturally;
print nsort <DATA>;
__DATA__
fw_d.log
fw_d.log.101.gz
fw_d.log.1.gz
fw_d.log.10.gz
fw_d.log.100.gz
fw_d.log.2.gz
fw_d.log.102.gz
fw_d.log.12.gz
такие заказы как:
fw_d.log
fw_d.log.1.gz
fw_d.log.2.gz
fw_d.log.10.gz
fw_d.log.12.gz
fw_d.log.100.gz
fw_d.log.101.gz
fw_d.log.102.gz