将IP地址列表按唯一网段合并为主机地址范围
解决方案
完整实现代码
import socket import struct from collections import defaultdict # 原始IP列表 ips = ["10.135.0.80","10.135.0.81","10.135.0.83","10.135.1.200","10.135.1.220","10.160.150.2","10.160.150.7","10.255.255.2"] # 按IP数值排序(你已实现的部分) sorted_ips = sorted(ips, key=lambda ip: struct.unpack("!L", socket.inet_aton(ip))[0]) # 按网段分组:键为"前三个段"的字符串,值为该网段下的IP列表 network_groups = defaultdict(list) for ip in sorted_ips: parts = ip.split('.') network = '.'.join(parts[:3]) # 提取/24网段标识 network_groups[network].append(ip) # 生成范围列表(字符串格式) range_str_list = [] # 生成元组格式的范围列表 range_tuple_list = [] for net, ip_list in network_groups.items(): min_ip = ip_list[0] max_ip = ip_list[-1] range_str_list.append(f"{min_ip}-{max_ip}") range_tuple_list.append((min_ip, max_ip)) # 输出结果 print("字符串格式的IP范围:") print(range_str_list) print("\n元组格式的IP范围:") print(range_tuple_list)
代码说明
- IP排序:保留你已实现的基于
socket.inet_aton和struct.unpack的排序逻辑,确保IP按数值从小到大排列,同一网段内的IP也会按顺序排列。 - 网段分组:
- 使用
defaultdict(list)自动创建网段对应的IP列表,避免手动判断网段是否存在。 - 通过
ip.split('.')拆分IP,取前三个部分拼接成网段标识(比如10.135.0),比正则表达式更简洁高效。
- 使用
- 生成范围:
- 因为IP已经排序,每个网段的IP列表第一个元素就是该网段的最小IP,最后一个元素就是最大IP。
- 分别生成你需要的字符串格式和元组格式结果,单个IP的网段会自动生成首尾相同的范围。
运行结果
字符串格式的IP范围: ['10.135.0.80-10.135.0.83', '10.135.1.200-10.135.1.220', '10.160.150.2-10.160.150.7', '10.255.255.2-10.255.255.2'] 元组格式的IP范围: [('10.135.0.80', '10.135.0.83'), ('10.135.1.200', '10.135.1.220'), ('10.160.150.2', '10.160.150.7'), ('10.255.255.2', '10.255.255.2')]
对你现有代码的改进点
你之前提取网段和主机的方式过于繁琐,且把所有主机部分放在一个列表里,无法直接对应到所属网段。改用按网段分组存储IP的方式,能直接关联每个网段下的所有IP,后续取首尾生成范围就非常直观,也避免了生成过多无效范围的问题。
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

