You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python脚本开发需求:检测重叠子网并筛选非重叠子网

高效解决子网重叠检查的Python方案

嘿,这个问题我熟!用Shell处理几千个子网的重叠检查确实会慢得离谱——毕竟Shell脚本大多是逐行遍历+字符串匹配,时间复杂度是O(nm),40004000就是1600万次操作,不卡才怪。

给你一个用Python实现的高效方案,核心思路是把子网转换成IP范围的整数,排序后用二分查找快速排查重叠,性能能提升好几个数量级。

实现思路

  1. 解析CIDR为整数范围:把每个子网转换成起始IP和结束IP的整数形式(IP本质就是32位整数,转换后方便快速比较)。
  2. 排序基准子网:将file1的所有子网范围按起始IP排序,这样可以用二分查找快速定位可能重叠的区间,避免全量遍历。
  3. 快速重叠检查:对file2的每个子网,用二分查找缩小需要检查的基准范围,只对比可能重叠的区间,大幅减少计算量。

完整代码

import ipaddress
import bisect

def cidr_to_ip_range(cidr):
    """将CIDR格式的子网转换成起始IP、结束IP的整数形式"""
    try:
        # strict=False 允许非标准网络地址的CIDR(比如192.168.1.5/24会自动转为192.168.1.0/24)
        net = ipaddress.IPv4Network(cidr.strip(), strict=False)
        start_ip = int(net.network_address)
        end_ip = int(net.broadcast_address)
        return (start_ip, end_ip)
    except ValueError as e:
        print(f"跳过无效CIDR: {cidr.strip()},错误信息: {str(e)}")
        return None

def load_benchmark_subnets(file_path):
    """加载并处理基准子网文件(file1),返回排序后的IP范围列表"""
    subnet_ranges = []
    with open(file_path, 'r', encoding='utf-8') as f:
        for line in f:
            line = line.strip()
            if not line:
                continue
            ip_range = cidr_to_ip_range(line)
            if ip_range:
                subnet_ranges.append(ip_range)
    # 按起始IP从小到大排序,为二分查找做准备
    subnet_ranges.sort()
    return subnet_ranges

def has_overlap(target_range, benchmark_ranges):
    """检查目标子网范围是否与基准子网列表中的任何范围重叠"""
    target_start, target_end = target_range
    # 用二分查找找到第一个起始IP大于目标结束IP的位置,前面的区间才可能重叠
    idx = bisect.bisect_right(benchmark_ranges, (target_end, float('inf')))
    # 只检查0到idx-1的区间
    for i in range(idx):
        bench_start, bench_end = benchmark_ranges[i]
        # 区间重叠条件:目标起始 <= 基准结束 且 基准起始 <= 目标结束
        if target_start <= bench_end and bench_start <= target_end:
            return True
    return False

def main():
    # 加载基准子网(file1)
    benchmark_ranges = load_benchmark_subnets('file1')
    print(f"成功加载 {len(benchmark_ranges)} 个有效基准子网")
    
    # 处理file2,输出无重叠子网到file3
    with open('file2', 'r', encoding='utf-8') as f_in, open('file3', 'w', encoding='utf-8') as f_out:
        count_total = 0
        count_valid = 0
        count_no_overlap = 0
        for line in f_in:
            count_total +=1
            line = line.strip()
            if not line:
                continue
            target_range = cidr_to_ip_range(line)
            if not target_range:
                continue
            count_valid +=1
            if not has_overlap(target_range, benchmark_ranges):
                f_out.write(f"{line}\n")
                count_no_overlap +=1
        print(f"处理完成:共读取 {count_total} 行,有效子网 {count_valid} 个,无重叠子网 {count_no_overlap} 个已写入file3")

if __name__ == '__main__':
    main()

关键优化点

  • 整数化IP:把IP转换成整数后,比较和排序的效率远高于字符串操作,这是性能提升的核心。
  • 二分查找缩小范围:原本需要对比4000+个基准子网,现在通过二分查找只需要对比少数几个可能重叠的区间,时间复杂度从O(n*m)降到O(n log n + m log n),对于4000个基准子网,每个file2子网的检查次数可能只有几次到几十次。
  • 内置模块加持:ipaddress是Python官方内置的模块,处理CIDR解析、IP范围计算非常高效且可靠,比Shell里用awk/grep拼接字符串的方式稳定得多。

注意事项

  • 如果需要严格检查CIDR是否为标准网络地址(比如拒绝192.168.1.5/24这种非网络起始地址的CIDR),可以把cidr_to_ip_range函数里的strict=False改成strict=True,这样会自动过滤掉这类非标准CIDR。
  • 要处理IPv6子网的话,只需要把ipaddress.IPv4Network改成ipaddress.IPv6Network即可,其他逻辑完全通用。
  • 如果file2的子网数量特别大(比如十万级以上),可以考虑用多线程/多进程并行处理,但一般单线程已经足够应对几千到几万条的规模了。

内容的提问来源于stack exchange,提问作者lendoiro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:30:41