求助:将大量零散IP/子网合并为完整子网的脚本优化问题
问题解决:IP地址与子网的批量合并优化
原脚本的核心问题
- 未处理输入中的子网条目:原脚本默认所有输入都是单个IP,无法解析
xx2.24.7.0/23这类子网格式,会直接报错或错误处理。 - 仅支持/24子网合并:没有考虑/22、/23、/25等其他掩码的完整子网检测。
- 未去重与优先级处理:输入中可能同时存在子网和单个IP,原脚本未做去重,也没有按从大到小的子网优先级合并,导致大网段无法被正确识别。
修正方案
实现思路
- 统一解析输入:区分单个IP和子网,将所有条目转换为IPv4地址集合,自动去重。
- 按优先级检测完整子网:从大掩码(/22)到小掩码(/25)依次检查,确保大网段优先被识别,避免被拆分为小网段。
- 标记已处理IP:每识别一个完整子网,就将该子网内的所有IP从集合中移除,避免重复处理为单个IP。
- 输出剩余单个IP:未被子网覆盖的IP以
/32格式输出。
修正后的代码
import ipaddress from collections import defaultdict def parse_input(input_lines): # 存储所有存在的IP,用集合去重 existing_ips = set() # 存储输入中已经存在的子网(后续要优先检查这些子网是否完整) input_subnets = set() for line in input_lines: line = line.strip() if not line: continue try: # 尝试解析为子网 net = ipaddress.IPv4Network(line, strict=False) input_subnets.add(net) # 将子网内的所有IP加入集合 for ip in net.hosts(): existing_ips.add(ip) except ValueError: # 解析失败则当作单个IP处理 try: ip = ipaddress.IPv4Address(line) existing_ips.add(ip) except ValueError: print(f"无效条目,跳过:{line}") continue return existing_ips, input_subnets def find_complete_subnets(existing_ips, input_subnets): # 定义需要检查的子网掩码,按从大到小优先级排列 prefix_lengths = [22, 23, 24, 25] complete_subnets = set() # 复制IP集合用于修改 remaining_ips = existing_ips.copy() # 先检查输入中已有的子网是否完整 for net in input_subnets: if net.prefixlen not in prefix_lengths: continue # 检查子网内所有主机IP是否都存在 all_present = True for ip in net.hosts(): if ip not in remaining_ips: all_present = False break if all_present: complete_subnets.add(net) # 移除已处理的IP for ip in net.hosts(): remaining_ips.discard(ip) # 再自动检测所有可能的完整子网 for prefix in prefix_lengths: # 按当前掩码分组剩余IP ip_groups = defaultdict(set) for ip in remaining_ips: # 获取IP所属的当前掩码子网 subnet = ipaddress.IPv4Network((ip, prefix), strict=False) ip_groups[subnet].add(ip) # 检查每个分组是否是完整子网 for subnet, ips in ip_groups.items(): # 计算该子网应有的主机数(总IP数减网络地址和广播地址) expected_hosts = 2 ** (32 - prefix) - 2 if len(ips) == expected_hosts: complete_subnets.add(subnet) # 移除已处理的IP remaining_ips -= ips return complete_subnets, remaining_ips def write_results(complete_subnets, remaining_ips, output_file): with open(output_file, "w") as f: # 先写入完整子网,按掩码从大到小排序 sorted_subnets = sorted(complete_subnets, key=lambda x: (x.prefixlen, x.network_address)) for subnet in sorted_subnets: f.write(f"{subnet}\n") # 写入剩余的单个IP,按地址排序 sorted_ips = sorted(remaining_ips) for ip in sorted_ips: f.write(f"{ip}/32\n") def main(input_file, output_file): with open(input_file, "r") as f: input_lines = f.readlines() existing_ips, input_subnets = parse_input(input_lines) complete_subnets, remaining_ips = find_complete_subnets(existing_ips, input_subnets) write_results(complete_subnets, remaining_ips, output_file) if __name__ == "__main__": input_file = "input.txt" output_file = "output.txt" main(input_file, output_file)
代码说明
parse_input函数:负责解析所有输入条目,将子网展开为IP集合,同时记录输入中已有的子网,自动过滤无效条目。find_complete_subnets函数:- 优先检查输入中已有的子网是否完整,确保用户预定义的网段优先被处理。
- 按/22→/23→/24→/25的顺序自动检测完整子网,避免小网段先被识别导致大网段无法合并。
- 每识别一个完整子网,立即移除对应IP,避免重复处理。
write_results函数:按掩码从大到小排序输出子网,按IP地址排序输出剩余单个IP,保证结果整洁有序。
内容的提问来源于stack exchange,提问作者mcalavera
相关产品推荐
相关产品推荐

