在 Perl 中高效排序的关键是创建一个函数,将要排序的值转换为可以按字典顺序排序的代表性字符串。
例如,如果要对日期进行排序,可以将它们转换为 yyyymmdd 格式。在这种情况下,我们将重新排序域的各个部分,以便
foo.bar.apple1.co.uk
成为以下之一:
# Using this approach, the sorted order of apple1.com and apple1.net will vary.
apple1.bar.foo
# Using this approach, the sorted order of apple1.com and apple1.net will be consistent.
apple1.bar.foo<NUL>uk.co
我们希望数字自然排序(1、2、10 而不是 1、10、2)。我们的关键函数可以处理这个问题,但我们将通过将sort 替换为Sort::Key::Natural 中的natkeysort 来采取简单的方法。作为奖励,natkeysort 允许我们轻松集成我们的关键功能!
困难的部分是识别后缀。没有规则,只是不断变化的定义。因此,我们将使用一个模块来识别后缀。
使用Domain::PublicSuffix实现按键功能:
use feature qw( state );
use Domain::PublicSuffix qw( );
sub get_sort_key {
my ($host) = @_;
$host =~ s/\.\z//;
state $dps = Domain::PublicSuffix->new();
$dps->get_root_domain($host)
or die "$host: ".$dps->error();
my @name = split /\./, substr($host, 0, -length($dps->suffix())-1);
my @suffix = split /\./, $dps->suffix();
return join('.', reverse @name)."\0".join('.', reverse @suffix);
}
使用IO::Socket::SSL::PublicSuffix实现按键功能:
use feature qw( state );
use IO::Socket::SSL::PublicSuffix qw( );
sub get_sort_key {
my ($host) = @_;
my @host = split(/\./, $host);
state $ps = IO::Socket::SSL::PublicSuffix->default();
my ($name, $suffix) = $ps->public_suffix(\@host);
return join('.', reverse @$name)."\0".join('.', reverse @$suffix);
}
以上函数使用如下:
use feature qw( say );
use Sort::Key::Natural qw( natkeysort );
my @hosts = (
'www.apple3.net',
'www.apple3.com',
'this.apple4.com',
'that.apple4.com',
'www.apple10.com',
'that.apple1.uk',
'and.that.apple2.com.br',
);
my @sorted_hosts = natkeysort { get_sort_key($_) } @hosts;
say for @sorted_hosts;
输出:
that.apple1.uk
and.that.apple2.com.br
www.apple3.com
www.apple3.net
that.apple4.com
this.apple4.com
www.apple10.com
IO::Socket::SSL::PublicSuffix 应该比Domain::PublicSuffix(和Mozilla::PublicSuffix)更频繁地更新,但它是更大发行版的一部分。