javascript 比较IP范围列表并将其缩短为唯一范围

2exbekwf  于 2023-01-24  发布在  Java
关注(0)|答案(1)|浏览(119)

我有一个IP范围列表(取自CIDR,脚本提供了起始地址和结束地址),我正在尝试获取唯一范围(目前是手动操作)

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

第3行118.187.0.0-118.187.63.255和第4行118.187.64.0-118.187.127.255可以缩短为118.187.0.0-118.187.127.255,因为63.255 (+1) is 64.0
有谁能给予我一个提示,这是如何通过脚本完成的?
当前的方法是通过将第一比较的ip“加一”并检查它是否与第二比较的ip相同来比较线3第二ip与线4第一ip

// 118.187.63.255 (+1) = 118.187.64.0
var x = "118.187.63.255".split('.')
var y = "118.187.64.0".split('.')
var compare=0;
var thesamerange=0;
for(var i=0;i<4;i++){
  if(x[i] === y[i]){
    compare=0;
  }else{
    if((parseInt(x[i])+1)===parseInt(y[i])){
      compare=1 }
  }
  if(compare === 1){
    if( (x[i+1])==255 && (y[i+1])==0 ){
      thesamerange=1 }
  }
}

有没有一种更简单的方法来“缩短列表”的唯一范围?

0yg35tkg

0yg35tkg1#

以下是一些提示,可以帮助您自己解决问题:

  1. IP地址可以完全转换为数字,反之亦然。(Explanation for Java)。
    1.检查范围是否按whether one's endpoint is included in the other range重叠(应连接)。
    如果你想要一个完整的指南,告诉你如何解决你的问题,请继续阅读。

连接范围

可以加入什么?

首先,我们需要决定可以连接哪些范围,包括:

  • 重叠的范围:
  • 部分重叠范围。
  • 一个范围是另一个范围的子范围。
  • 端点为紧邻的范围。("接触"的范围。)
    • 旁注**:这两个语句是等效的:

1.范围[a1, a2][b1, b2]相邻。
1.范围[a1, a2](部分)与[b1 - 1, b2 + 1]重叠(反之亦然)。
在"extension"(语句2)之后,重叠范围仍然会重叠。我们稍后将使用这一点。

转换为更简单的类型

现在我们知道了加入的条件,我们需要能够检查它们。
为了便于检查,我们可以将IP地址转换为整数:

      • 来自点标记法**:

将IP地址解释为以256为基数的4位数字,其中数字是以点分隔的整数。
1.* * 点标记法**:
1.将number解析为8位十六进制数(必要时带前导零)。
1.将每两个16进制数字解释为一个256进制数字。
1.将四个256进制数字解析为数字。
1.用点把数字连起来。

const ip = "192.168.0.1";

console.log("IP:", ip);
console.log("IP as number:", fromIp(ip));
console.log("IP after roundtrip:", toIp(fromIp(ip)));

function fromIp(ip) {
  const numbers = ip.split(".").map(split => Number(split));
  
  const ipAsNumber = numbers.reverse().reduce((total, number, i) => {
    return total + number * (256 ** i);
  }, 0);
  
  return ipAsNumber;
}
function toIp(number) {
  const numberInHex = number.toString(16).padStart(8, "0");
  
  const hexSplits = Array.from({length:4}, (v, i) => numberInHex.slice(i * 2, i * 2 + 2));
  const ipSplits = hexSplits.map(hex => parseInt(hex, 16));
  
  return ipSplits.join(".");
}

如何检查可接合性

如果我们将条件可视化,实现检查可能会变得更容易理解:

注意线A、C、D是如何与线B连接的。它们的共同点(抽象地)是:

  • 可连接线的左端在B右端的左边。
  • 可连接线的右端在B左端的右边。

或者,在代码中:
x一个一个一个一个x一个一个二个x

加入

有了上面的章节,我们可以很容易地找到哪些范围可以连接。但我们仍然必须实际地将它们连接在一起。
为此,我们可以使用Array.reduce()收集(连接的)范围,如下所示:
一个三个三个一个

终于

把所有东西放在一起:
1.从IP地址范围转换为数字范围。
1.联接区域:
1.如果当前范围不可连接,则收集。
1.否则,与可连接范围连接。
1.将可连接区域替换为已连接区域。
1.对从2开始的连接范围重复此操作。
1.从数字范围转换

const ipRanges = [
  { from: "118.184.192.0", to: "118.184.223.255" },
  { from: "118.187.0.0", to: "118.187.255.255" },
  { from: "118.187.0.0", to: "118.187.63.255" },
  { from: "118.187.64.0", to: "118.187.127.255" },
  { from: "118.191.4.0", to: "118.191.5.255" },
  { from: "118.191.6.0", to: "118.191.7.255" },
  { from: "118.191.8.0", to: "118.191.11.255" },
  { from: "118.191.12.0", to: "118.191.12.255" }
];

const numberRanges = ipRanges.map(({ from, to }) =>
  ({ from: fromIp(from), to: fromIp(to) })
);

const joinedRanges = reduceRanges(numberRanges);

const joinedIpRanges = joinedRanges.map(({ from, to }) =>
  ({ from: toIp(from), to: toIp(to) })
);

console.log("IP-ranges:", ipRanges );
console.log("Reduced IP-ranges:", joinedIpRanges);

function reduceRanges(rangesToReduce) {
  const reducedRanges = rangesToReduce.reduce((ranges, range) => {
    let joinWith = range;
    const nextJoinableRange = () => ranges.find(r =>
      r !== joinWith && isJoinable(r, joinWith)
    );
    
    let joinableRange = nextJoinableRange();
    
    if (!joinableRange) {
      ranges.push(range);
      return ranges;
    }
    
    do {
      const index = ranges.indexOf(joinableRange);
      ranges.splice(index, 1);
      
      const joinedRange = {
        from: Math.min(joinableRange.from, joinWith.from),
        to: Math.max(joinableRange.to, joinWith.to)
      };
      ranges.push(joinedRange);
      
      joinWith = joinedRange;
    } while (joinableRange = nextJoinableRange());
    
    return ranges;
  }, []);
  
  return reducedRanges;
}

function isJoinable(range1, range2) {
  return (range1.from - range2.to) <= 1 && (range2.from - range1.to) <= 1;
}

function fromIp(ip) {
  const numbers = ip.split(".").map(split => Number(split));

  const ipAsNumber = numbers.reverse().reduce((total, number, i) => {
    return total + number * (256 ** i);
  }, 0);

  return ipAsNumber;
}
function toIp(number) {
  const numberInHex = number.toString(16).padStart(8, "0");

  const hexSplits = Array.from({length:4}, (v, i) => numberInHex.slice(i * 2, i * 2 + 2));
  const ipSplits = hexSplits.map(hex => parseInt(hex, 16));

  return ipSplits.join(".");
}
.as-console-wrapper {max-height:100%!important}

此答案仅包括如何加入IP地址范围。
从答案中可以明显看出,您收到的范围是特定格式的(范围为start-end,每行一个)。您可能仍然希望将该格式转换为更易于处理的对象。请将此作为练习!

相关问题