如何按字符串中的数字对字符串列表进行排序?

发布于 2024-11-14 09:33:08 字数 983 浏览 5 评论 0原文

我有一个文件名列表,如下所示:

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 $configs\n";
        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  

正如您所看到的,它几乎按照我想要的方式对其进行排序希望...有人对阅读或我可以使用的代码片段有任何建议吗?

I have a list of filenames which are like so:

fw_d.log.1.gz  
through  
fw_d.log.300.gz  

When I use this code block below, it almost sorts it the way I want, but not quite:

#!/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 $configs\n";
        system("less $basedir/$combidir/$configs | grep \'.* Group = , Username = .* autheauthenticated.\' >> output.log" );
    }
}

Here is a snippet output:

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  

As you can see, it almost sorts it how I was hoping... Does anyone have any suggestions, on either reading, or a code snippet I can use?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

因为看清所以看轻 2024-11-21 09:33:08

您可以使用 Schartzian-transform

my @sorted = map  { $_->[0] }
             sort { $a->[1] <=> $b->[1] }
             map  { [$_, $_=~/(\d+)/] }
                 @files;
print Dumper \@sorted;

添加了 Schwartzian-Transform 和子例程之间比较的基准

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", $1}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%          --

对于 300 个文件进行排序,Schwartzian 变换的效率大约提高了 13 倍。

You could use Schartzian-transform :

my @sorted = map  { $_->[0] }
             sort { $a->[1] <=> $b->[1] }
             map  { [$_, $_=~/(\d+)/] }
                 @files;
print Dumper \@sorted;

Added benchmark for comparison between Schwartzian-Transform and subroutine

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", $1}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;
         }
});

Result:

              Rate     subname schwartzian
subname     21.2/s          --        -92%
schwartzian  279/s       1215%          --

Schwartzian-transform is about 13 times more efficient for sorting 300 files.

欢你一世 2024-11-21 09:33:08

问题是代码执行了您告诉它执行的操作:按字母顺序对文件名进行排序。

您应该将 sort { $a cmp $b } 替换为 sort { Expand($a) cmp Expand($b) }

expand

sub expand 
   { my $file=shift; 
     $file=~s{(\d+)}{sprintf "%04d", $1}eg; # expand all numbers to 4 digits
     return $file;
   }

the problem is that the code does what you tell it to do: sort the file names in alphabetical order.

You should replace sort { $a cmp $b } by sort { expand($a) cmp expand($b) }

with expand:

sub expand 
   { my $file=shift; 
     $file=~s{(\d+)}{sprintf "%04d", $1}eg; # expand all numbers to 4 digits
     return $file;
   }
怪异←思 2024-11-21 09:33:08

您可以尝试使用自定义排序函数:

sub sort_by_number {
    $a =~ /(\d+)/;
    $numa = $1;
    $b =~ /(\d+)/;
    $numb = $1;

    return $numa <=> $numb;
}

然后像这样排序:

@files1 = sort sort_by_number @files;

这将按每个字符串中第一个数字的值对 @files 中的字符串进行排序。

What you can try is using a custom sort function:

sub sort_by_number {
    $a =~ /(\d+)/;
    $numa = $1;
    $b =~ /(\d+)/;
    $numb = $1;

    return $numa <=> $numb;
}

and then sort like this:

@files1 = sort sort_by_number @files;

This will sort the strings in @files by the value of the first number in each string.

薄荷港 2024-11-21 09:33:08

较旧的问题,但尚未提及答案。

排序::自然 为您执行此操作:

按词法排序,但按数字排序数字部分

#!/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  

Older question, but there's an answer as yet unmentioned.

Sort::Naturally does this for you:

Sort lexically, but sort numeral parts numerically

#!/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

This orders as:

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  
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文