在Perl中对文件名进行排序?

时间:2015-01-30 03:57:37

标签: perl sorting file-io

我正在Perl中编写一个脚本,我希望在给定目录中的所有.csv文件上运行。文件名的类型为:CCCC0.csv, CCCC1.csv, ..., CCCC198.csv。但是,我希望Perl首先在文件CCCC0.csv上运行脚本,而不是在CCCC1.csv等上运行...所以,基本上,根据文件名末尾的数字的增加值。 如果我写:

#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

my $file;
my @files = <*.csv>;
my @orderedfiles = sort @files;
for $file (@orderedfiles) {

... do stuff

}

如果我写

,它首先在CCCC100.csv而不是CCCC11.csv上运行
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

my $file;
my @files = <*.csv>;
my @orderedfiles = sort { substr($a, 4) <=> substr($b, 4)  } @files;
for $file (@orderedfiles) {

... do stuff

}

它给我一个错误,告诉我我没有订购数字(我认为他不明白它是4个字符之后的数字而不是另一个字符。) 我已经看过Stackoverflow或perlmonks处理排序的无数问题,但我无法找到问题的答案。

编辑:我正在使用Windows机器。

3 个答案:

答案 0 :(得分:6)

你几乎就在那里......“。CSV”仍在那里。使用正则表达式来阅读数字字符会更好。

my @sorted = sort { ($a =~ /(\d+)/)[0] <=> ($b =~ /(\d+)/)[0] } @files;

有一个叫Schwartzian Transform的成语也可以做到这一点,虽然它需要CS专业才能理解:D

my @sorted = map  { $_->[0] }             # return the sorted file names
                                          #
             sort { $a->[1] <=> $b->[1] } # sort on the numeric portion
                                          #
             map  { [$_, /(\d+)/] }       # wrap the file names in a temporary 
             @files;                      #   array with their numeric portions.

                                          # ^^ read from bottom to top ^^

答案 1 :(得分:3)

你可以给Sort::Key::Natural一个旋转。从概要:

use Sort::Key::Natural qw(natsort);

my @data = qw(foo1 foo23 foo6 bar12 bar1
              foo bar2 bar-45 foomatic b-a-r-45);

my @sorted = natsort @data;

print "@sorted\n";
# prints:
#   b-a-r-45 bar1 bar2 bar12 bar-45 foo foo1 foo6 foo23 foomatic

答案 2 :(得分:2)

我相信substr($ a,4)正在返回&#34; 100.csv&#34;在你的例子中,所以你需要修剪.csv后缀。