如何通过脚本合并相邻/重叠IP范围,生成唯一精简IP范围列表?
精简IP地址范围的高效方法
要实现自动合并重叠或连续的IP范围,更简洁高效的思路是将IP地址转换为32位整数,通过数值对比来处理合并逻辑,具体步骤如下:
核心步骤
- IP转数值:将每个IP地址转换为无符号32位整数,这样可以直接用数值运算判断连续性或重叠性,避免逐段解析IP字符串的繁琐。
- 排序范围:按起始IP的数值从小到大排序所有范围,确保后续可以按顺序处理。
- 合并范围:遍历排序后的范围,维护当前合并中的范围,若下一个范围与当前范围重叠或连续,则合并;否则将当前范围存入结果,开始处理下一个新范围。
完整JavaScript实现
// 将IP字符串转换为32位无符号整数 function ipToNumber(ip) { return ip.split('.').reduce((acc, octet) => (acc << 8) + parseInt(octet, 10), 0) >>> 0; } // 将32位整数转换回IP字符串 function numberToIp(num) { return [ (num >> 24) & 0xff, (num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff ].join('.'); } // 合并IP范围 function mergeIpRanges(ranges) { // 转换所有范围为数值格式 const numericRanges = ranges.map(range => { const [startIp, endIp] = range.split('-'); return { start: ipToNumber(startIp), end: ipToNumber(endIp) }; }); // 按起始IP排序 numericRanges.sort((a, b) => a.start - b.start); if (numericRanges.length === 0) return []; const merged = [numericRanges[0]]; for (let i = 1; i < numericRanges.length; i++) { const current = merged[merged.length - 1]; const next = numericRanges[i]; // 判断是否重叠或连续:下一个范围的起始 <= 当前范围的结束 +1 if (next.start <= current.end + 1) { // 合并,更新结束值为两者的最大值 current.end = Math.max(current.end, next.end); } else { // 无法合并,加入新范围 merged.push(next); } } // 转换回IP字符串格式 return merged.map(range => `${numberToIp(range.start)}-${numberToIp(range.end)}`); } // 测试示例 const inputRanges = [ "118.184.192.0-118.184.223.255", "118.187.0.0-118.187.255.255", "118.187.0.0-118.187.63.255", "118.187.64.0-118.187.127.255", "118.191.4.0-118.191.5.255", "118.191.6.0-118.191.7.255", "118.191.8.0-118.191.11.255", "118.191.12.0-118.191.12.255" ]; console.log(mergeIpRanges(inputRanges));
输出结果
运行上述代码后,会得到合并后的精简IP范围:
[ "118.184.192.0-118.184.223.255", "118.187.0.0-118.187.255.255", "118.191.4.0-118.191.12.255" ]
优势说明
- 逻辑简洁:数值化处理避免了逐段解析IP的复杂判断,连续或重叠的判断只需简单的数值比较。
- 覆盖所有场景:不仅能合并连续的范围,还能处理完全包含的重叠范围(如示例中118.187的大范围包含两个小范围)。
- 高效可扩展:排序后单次遍历即可完成合并,时间复杂度主要由排序决定(O(n log n)),适合处理大规模IP范围列表。
内容的提问来源于stack exchange,提问作者adrian3k
相关产品推荐
相关产品推荐

