配列に格納された一連の IP アドレスがあります。
my @ip = qw(10.11.1.1 10.100.1.1 ...);
アドレスを昇順に並べ替えるにはどうすればよいですか? 私は簡単に試しましたsort
が、もちろん失敗しました。
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;
最初のものもドメイン名を受け入れます。
必要以上のことを想定したソリューションは好きではありません。私は以前からこの種のコンパクト表記に悩まされてきましたが、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
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 );
Sort::Key::IPv4を使用する
ソフトウェアのバージョン番号を並べ替えるように設計されたモジュールがあります。多分それはあなたが望むことをしますか?
これで良いスタートが切れるはずです:
#!/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";