(Powershell) 对 IP 地址数组进行排序

问题描述 投票:0回答:2

我需要对 IP 地址数组进行排序,并输出排序后的数组以在每个 IP 地址之间包含“,”

$ip = "192.168.0.10, 192.168.0.12, 192.168.0.11, 192.168.0.9"
$ip =$ip.ToString()
$a = $ip.Split(",")
$new = for ($i=0;$i -lt $a.count;$i+=1) {$a[$i]}
$new | sort

输出以下内容(请注意,第 4 个 IP 八位字节未正确排序):

192.168.0.11
192.168.0.12
192.168.0.9
192.168.0.10

带有“,”分隔符的预期(已排序)输出:

“192.168.0.9”、“192.168.0.10”、“192.168.0.11”、“192.168.0.12”

谢谢您的帮助!

arrays powershell sorting
2个回答
1
投票

IP 地址的排序方式与版本相同。在排序中投射项目效果很好:

$ip = "192.168.0.10, 192.168.0.12, 192.168.0.11, 192.168.0.9"
$ip =$ip.ToString()
$a = $ip.Split(",")
$new = for ($i=0;$i -lt $a.count;$i+=1) {$a[$i]}
$new | sort {[Version]$_}

顺便说明一下,.ToString() 和 for 循环是不必要的。以下结果相同。

$ip = "192.168.0.10, 192.168.0.12, 192.168.0.11, 192.168.0.9"
$new = $ip.Split(",")
$new | sort {[Version]$_}

1
投票

你有两件事发生:

前导空格

当您分割字符串时,您还需要修剪它 - 您实际排序的值是:

192.168.0.10
 192.168.0.12
 192.168.0.11
 192.168.0.9

注意第 2-4 项的前导空格。

 
(空格)字符在1字符之前
排序,因此
192.160.0.10
最终位于列表的底部,排序结果为:

192.168.0.11 192.168.0.12 192.168.0.9 192.168.0.10
您可以通过

Trim()

修改您的值以删除任何前导或尾随空格来解决此问题:

$a = $ip.Split(",").Trim()
(这使用 

Member-Access Enumeration 来修剪分割结果中的所有值,并使用 Trim()

 的结果创建一个新数组,所以现在我们的输出是:

192.168.0.10 192.168.0.11 192.168.0.12 192.168.0.9
看起来好一点,但由于不同的原因它仍然是错误的......

词法排序

您的排序正在进行

词法(字典)排序,而不是 IP 地址八位字节的语义排序。

由于您的所有地址都有相同的前 3 个八位字节,如果我们对最后一个八位字节进行排序,我们会得到:

"10, 12, 11, 9".Split(",").Trim() | sort 10 11 12 9
基本上,

9

1
 进行排序,因此 
9
 出现在 
10
11
12
 之后。

有关稍微复杂一点的示例,请参见:

"1, 2, 10, 11, 12, 20, 21, 22, 100, 200".Split(",").Trim() | sort 1 10 100 11 12 2 20 200 21 22 3
所有内容均按字符串中的第一个字符排序,

then按第二个字符排序,then按第三个字符排序,而不是按它们的数值排序。

回答

要根据八位字节的数值而不是字符串中的文字字符进行语义排序,您需要将字符串

解析为您想要的排序形式。

幸运的是,您可以将 IP 地址字符串转换为根据八位字节值排序的

[int]

 - 请参阅 
https://stackoverflow.com/a/36560061/3156906

您还可以根据输入数组对计算值进行排序 - 将这两个放在一起给出:

$ip = "192.168.0.10, 192.168.0.12, 192.168.0.11, 192.168.0.9"; $ip.Split(",").Trim() | sort-object { # from https://stackoverflow.com/a/36560061/3156906 $bytes = [System.Net.IPAddress]::Parse($_).GetAddressBytes(); if( [BitConverter]::IsLittleEndian ) { [Array]::Reverse($bytes); } [BitConverter]::ToUInt32($bytes, 0); } 192.168.0.9 192.168.0.10 192.168.0.11 192.168.0.12
这也适用于其他一些问题,例如:

$ip = "192.168.0.100, 192.168.0.12, 99.99.99.99, 192.168.0.9" $ip.Split(",").Trim() | sort-object { ... } # 99.99.99.99 # 192.168.0.9 # 192.168.0.12 # 192.168.0.100
    
© www.soinside.com 2019 - 2024. All rights reserved.