如何将IP地址列表转换为地址范围列表?
有很多方法可以把一组IP地址转换成CIDR格式的列表(比如用netaddr或ipaddr-py)。那么有没有办法把一组IP地址范围合并成一个更大的IP范围呢?
下面的例子会返回一个包含元组的列表,格式是: [(开始, 结束)]
。
例子1:
>>> list_of_ips = ['192.168.0.1', '192.168.0.2', '192.168.0.3']
>>> print merge_ip_list(list_of_ips)
[('192.168.0.1','192.168.0.3')]
例子2:
>>> list_of_ips2 = ['10.0.0.0', '10.0.0.3', '10.0.0.4']
>>> print merge_ip_list(list_of_ips2)
[('10.0.0.0','10.0.0.0'), ('10.0.0.3','10.0.0.4')]
1 个回答
3
在我看来,一个好的起点是把带点的字符串转换成整数,然后再把整数转换回字符串。用整数表示更方便进行比较。
我考虑过用reduce这个方法,但对我来说似乎太复杂了。所以我只是用传统的循环实现了这个功能,没有使用递归。
def int2dot( intip ):
return '.'.join([ str( (intip>>x*8) & 0xFF ) for x in [3,2,1,0]])
def dot2int( dotip ):
return reduce( lambda r,x: int(x)+(r<<8), dotip.split('.'), 0 )
def merge_ip_list(ip_list):
if not ip_list:
return []
orig = map(dot2int,ip_list)
orig.sort()
start = orig[0]
prev = start-1
res = []
for x in orig:
if x != prev+1:
res.append((int2dot(start),int2dot(prev)))
start = x
prev = x
res.append((int2dot(start),int2dot(prev)))
return res
另外,我还做了一个替代的解决方案:
def merge_ip_list_alt(ip_list):
if not ip_list:
return []
orig = sorted(map(dot2int,ip_list))
end, start = zip(*[x for x in zip(orig,orig[1:]) if x[0]+1!=x[1]]) or ((),())
start = [int2dot(orig[0])] + map(int2dot,start)
end = map(int2dot,end) + [int2dot(orig[-1])]
return zip( start, end )