序言:我讨厌提出这样的问题,但我坚持认为只是学习Perl ......看起来很容易,但我不知道在哪里看。
我有一个包含大量xml文件的文件夹,这些文件都被命名为“.xml”。 我需要按照数字顺序处理这些文件,因此“9123.xml”应该出现在“2384747.xml”之前。 我已成功按字母顺序对列表进行了排序:
opendir(XMLDIR,$xmldirname);
my @files = sort {$a cmp $b} readdir(XMLDIR);
但这不是我需要的。
我也试过
my @files = sort {$a <=> $b} readdir(XMLDIR);
显然失败了,因为文件名包含“.xml”并且不是整数数字。
有人可以敞开心扉,为我节省一周浏览Perl手册吗?
答案 0 :(得分:4)
尽管你声称,sort { $a <=> $b } readdir(XMLDIR)
仍有效。当Perl将字符串2384747.xml
视为数字(如<=>
所做的那样)时,它被视为具有值2384747
。
$ perl -wE'say 0+"2384747.xml"'
Argument "2384747.xml" isn't numeric in addition (+) at -e line 1.
2384747
当然,这些警告是个问题。您接受的解决方案会尝试删除它们,但未能删除所有这些解决方案,因为它没有考虑readdir
将返回.
和..
。你必须先删除你不想要的文件。
以下是两个简单的解决方案:
my @files =
sort { no warnings 'numeric'; $a <=> $b }
grep { /^(\d)\.xml/ }
readdir(XMLDIR);
my @files =
sort { ( $a =~ /(\d+)/ )[0] <=> ( $b =~ /(\d+)/ )[0] }
grep { /^(\d)\.xml/ }
readdir(XMLDIR);
在这种特殊情况下,您可以优化代码:
my @files =
map { "$_.xml" } # Recreate the file name.
sort { $a <=> $b } # Compare the numbers.
map { /^(\d)\.xml/ } # Extract the number from desired files.
readdir(XMLDIR);
最简单,最快速的解决方案是使用自然排序。
use Sort::Key::Natural qw( natsort );
my @files = natsort grep !/^\.\.?/, readdir(XMLDIR);
答案 1 :(得分:2)
你实际上非常接近。只需在比较中删除“.xml”:
opendir(XMLDIR,$xmldirname);
my @files = sort {substr($a, 0, index($a, '.')) <=> substr($b, 0, index($b, '.'))} readdir(XMLDIR);
答案 2 :(得分:1)
问题是<=>
无法处理非完全数字的内容,事实上如果你use warnings;
在运行时会得到类似于此的消息 - 时间:
Argument&#34; 11139.xml&#34;在testsort.pl第9行的sort中不是数字。
你可以做的是将文件名从扩展名中分离出来,在文件名中按数字排序然后重新组合扩展名。这可以通过Schwartzian transform
相当简单地完成:
use strict;
use warnings;
use Data::Dumper;
# get all of the XML files
my @xml_files = glob("*.xml");
print 'Unsorted: ' . Dumper \@xml_files;
@xml_files = map { join '.', @$_ } # join filename and extension
sort { $a->[0] <=> $b->[0] } # sort against filename
map { [split /\./] } @xml_files; # split on '.'
print 'Sorted: ' . Dumper \@xml_files;
__END__
Unsorted: $VAR1 = [
'11139.xml',
'18136.xml',
'28715.xml',
'6810.xml',
'9698.xml'
];
Sorted: $VAR1 = [
'6810.xml',
'9698.xml',
'11139.xml',
'18136.xml',
'28715.xml'
];
答案 3 :(得分:1)
my @files = sort {
my ($x) = split /\./, $a;
my ($y) = split /\./, $b;
$x <=> $y
} readdir(XMLDIR);
或没有临时变量:
my @files = sort {(split /\./, $a)[0] <=> (split /\./, $b)[0]} readdir(XMLDIR);