上篇提到纯真ip库有很多行是浪费的,比如下面这种:yaml
223.214.0.0 223.215.255.255 安徽省 电信
223.216.0.0 223.219.255.255 日本
223.220.0.0 223.220.162.1 青海省 电信
223.220.162.2 223.220.162.2 青海省海东地区 平安县九歌网吧
223.220.162.3 223.221.255.255 青海省 电信
很简单的223.220.0.0-223.221.255.255段,却被拆成了三行。于是在通过起始ip结束ip计算子网之前,还需要合并一下这些ip段。
因为涉及ip比对,所以第一反应想到了mysql里有的inet_aton函数,去CPAN上搜了一下,发现有NetAddr::IP::Util模块有inet_aton函数,结果一用,发现居然生成的不是数字……于是从网上找到了pack的办法,如下:
```perl#!/usr/bin/perl -w
while(<>){
next unless $_ =~ /^(\S+)\s+(\S+)\s+(\S+)/;
my $low = unpack(‘N’,(pack(‘C4’,(split( /./,$1)))));
#下面这行是IP::QQWry模块里的写法
my $high = unpack('N',(pack('C4',(split( /\./,$2)))));
next if $low == $high;
my $addr = $3;
unless ( $hash->{$addr}->{high}->[0] ) {
$hash->{$addr}->{low}->[0] = $low;
$hash->{$addr}->{high}->[0] = $high;
next;
}; #如果中间就隔几个ip的,可以无视之,合并就是了……
if ( $low - $hash->{$addr}->{high}->[0] < 16 ) {
$hash->{$addr}->{high}->[0] = $high;
next;
};
unshift @{$hash->{$addr}->{low}}, $low;
unshift @{$hash->{$addr}->{high}}, $high; }; foreach $addr ( keys %{$hash} ) {
my $i = 0;
while ( $hash->{$addr}->{low}->[$i] ) {
print $addr . "\t" . ¬a($hash->{$addr}->{low}->[$i]) . "\t" . ¬a($hash->{$addr}->{high}->[$i]) , "\n";
$i++;
} }; sub nota {
my $aton = shift;
@a = unpack('C4',(pack('N',$aton)));
return (join "\.",@a); };``` pack真复杂,基本看不懂perldoc,唉……
最后汇报一下运行结果: 合并前一共428452行,合并后103008行。