我有一堆存储在数组中的IP地址,例如:
my @ip = qw(10.11.1.1 10.100.1.1 ...);
如何按升序对地址进行排序?我尝试过一个简单的sort
但当然失败了。
答案 0 :(得分:11)
IPv4地址只是32位数字。
use Socket qw( inet_aton );
my @sorted =
map substr($_, 4),
sort
map inet_aton($_) . $_,
@ips;
或
my @sorted =
map substr($_, 4),
sort
map pack('C4a*', split(/\./), $_),
@ips;
第一个也接受域名。
答案 1 :(得分:6)
我不喜欢任何假设需要的解决方案。我之前通过紧凑的表示法对这种事情进行了刻录,我认为当IPv6变得更加普遍时,这个问题会变得更加严峻。我只是让Net::IP弄清楚:
use 5.010;
use Net::IP;
my @ip = qw(
192.168.1.10
172.16.5.5
256.0.0.1
192.168.1/24
127.1
127.0.1
fd00:6587:52d7:f8f7:5a55:caff:fef5:af31
fd24:cd9b:f001:884c:5a55:caff:fef5:af31
);
my @sorted =
map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [ $_, eval { Net::IP->new( $_ )->intip } ] }
@ip;
say join "\n", @sorted;
这样可以很好地处理紧凑和范围符号,eval
可以捕获错误的IP地址。我不必单独处理IPv4和IPv6:
256.0.0.1
127.0.1
127.1
172.16.5.5
192.168.1/24
192.168.1.10
fd00:6587:52d7:f8f7:5a55:caff:fef5:af31
fd24:cd9b:f001:884c:5a55:caff:fef5:af31
答案 2 :(得分:1)
只是IPv4地址?
my @ip = map $_->[0],
sort { $a->[1] cmp $b->[1] }
map [ $_, join '', map chr, split /\./, $_ ],
qw( 10.1.2.3 172.20.1.2 192.168.1.2 );
答案 3 :(得分:1)
答案 4 :(得分:1)
我正在寻找@ ikegami的答案,结果证明是完美的,但我不知道为什么。所以我花了一些时间来弄清楚它背后的机制,我想分享我的笔记,以供将来参考较小的Perl专家......
在这个例子中,我选择了两个非常具体的IP地址,因为当编码为ASCII时,它们看起来像ABCD
和EFGH
,如print Dumper()
行的输出所示。 / p>
技巧是为每个IP地址字符串添加4个包含其二进制表示的字节。然后对条目进行排序,最后再次删除前缀,留下已排序的IP地址列表。
评论中描述了内部工作原理,最好按编号顺序阅读。
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
my @ips = qw( 69.70.71.72 65.66.67.68 );
print Dumper( map( pack( 'C4a*' , split( /\./ ) , $_ ) , @ips ) );
foreach my $ip (
map( # 5. For each IP address that was enriched with 32 bits representation ....
substr( $_ , 4) , # 6. Snip off the first four bytes as this is just a binary representation of the string, used for sorting.
sort( # 4. Sort will essentially work on the first 4 octets as these will represent the entire remainder of the string.
map( # 1. For each IP address in @ARGV ...
pack( 'C4a*' , # 3. Change ASCII encoded octets from the IP address into a 32 bit 'string' (that can be sorted) and append it with the original IP address string for later use.
split( /\./ ), $_ ) , # 2. Split the IP address in separate octets
@ips # 0. Unsorted list of IP addresses.
)
)
)
) {
print "$ip\n";
}
输出结果如下:
$VAR1 = 'EFGH69.70.71.72';
$VAR2 = 'ABCD64.65.66.67';
64.65.66.67
69.70.71.72
前两行来自print Dumper()
,显示IP地址的前缀是数字IP地址的32位表示。
答案 5 :(得分:1)
updateTime
您可以将其反转... -r:-)
答案 6 :(得分:0)
这应该会给你一个良好的开端:
#!/usr/bin/perl
use strict;
use warnings;
sub Compare {
# TODO: Error checking
my @a = split /\./, $a;
my @b = split /\./, $b;
# TODO: This might be cleaner as a loop
return $a[0] <=> $b[0] ||
$a[1] <=> $b[1] ||
$a[2] <=> $b[2] ||
$a[3] <=> $b[3];
}
my @ip = qw( 172.20.1.2 10.10.2.3 10.1.2.3 192.168.1.2 );
@ip = sort Compare @ip;
print join("\n", @ip), "\n";
答案 7 :(得分:0)
有一个专为sort software version numbers设计的模块。也许这会做你想要的?