在Python中,我使用netaddr包来轻松进行ip地址比较和排序操作。例如:
IPAddress('1.2.3.4') < IPAddress('3.4.5.6')
IPAddress('1.2.3.4') is in IPNetwork('1.0.0.0/8')
现在我需要在 Javascript 中做同样的事情,而且我不想重新发明轮子..
我找不到一个可以轻松进行类似比较的节点包。我发现一些(如netmask)非常可靠,但仅限 IPv4。我需要支持 IPv4 和 IPv6 比较。
所以,我的要求是:
令我有点惊讶的是,四年过去了,这个问题还没有得到一个像样的答案。我曾经使用过其中一个,并且 lodash 和 ipaddr.js 之间的世界如此接近,因此我决定完成一个解决方案。它由 3.5 个部分组成并使用两个库。这可能看起来很繁重,但您可能已经有了 lodash,如果您需要对 IPv4 和 IPv6 地址进行排序,您可能已经可以从
ipaddr.js
中受益。
(我有点惊讶
ipaddr.js
还没有这方面的东西。如果人们喜欢这个并且没有人分享更好的解决方案,我愿意将其作为模块的增强提交)
TL/DR:
ipaddr.js
解析您的 IP 地址;产生可比较的零件 (xtets
)lodash.sortBy
进行紧凑的多维排序
family
属性作为第一个 iteratee
iteratees
数组,以比较 octets
生成的 parts
或 ipaddr.js
数组的连续元素。实施
// support fns/vars
const iteratees = [];
const xtet = n => (addr => (addr.octets || addr.parts)[n]);
for(let i=0; i<8; i++) iteratees.push(xtet(i));
// the actual IP address sort function
const sortAddrs = (addrs) => _.sortBy(addrs, [ 'family', ...iteratees ]);
// Example usage (100 < 2 in string sort)
const addrs = ['fed0:100::1', '10.100.0.1', 'fed0:2::1', '10.2.0.1'];
const parsed = addrs.map((a) => ipaddr.parse(a));
const sorted = sortAddrs(parsed);
console.log(sorted.map(a => a.toString()));
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ipaddr.js/2.1.0/ipaddr.min.js"></script>
ipaddr.js是一个强大的IP地址检查和操作库。第一步是解析地址。生成的对象具有
octets
(v4) 或 parts
(v6) 属性,这只是每个 xtet
的整数表示,最高阶在前。 (我可能刚刚创造了xtet
,我不确定)。
lodash.sortBy 让您直接关注排序比较的每次迭代,从而简化了复杂的排序。它需要一个集合和一个“迭代者”列表。仅当两个对象在先前的迭代器上继续相等时才会调用后续的迭代器。
我首先对系列进行排序,b/c 将 v4 地址与 v6 地址进行比较是没有意义的(没有额外的上下文来指示它们应该如何排序)。因此,
'family'
是第一个“迭代者”。
接下来,我们给出
sortBy
一个比较连续 xtets 的迭代数组。我的代码生成了一个由 8 个小函数组成的数组,每个函数返回 octets
或 parts
的第 n 个元素。这些是可直接用于排序目的的整数。
可能有一种更紧凑的方法来生成该数组,但我想不出一种方法。在该系列中,将一个 xtet 与另一个进行比较就像将地址转换为单个大整数一样正确。
注意:如果省略
family
迭代器,它似乎不会崩溃。然而我不认为结果有意义; v4 地址的第一个八位字节几乎总是小于 v6 地址的第一个十六进制,除了环回等极端情况。