2011年2月3日木曜日

◆IPアドレスをソートする

IPアドレスを含んだCSVファイルなどを読み込んでIPアドレス順にソートする。

IPAddressクラスなんかにキャストしたら簡単にできるのかと思ったのだがそうも行かないようだ。(気づかないだけかもしれないが)

とりあえず力技でやって見る。
それぞれのオクテットをプロパティとして持つオブジェクトを作ってそれでソートしてやれば良いだろう。
分割するのはSplitでも良いと思うのだが、ここでは正規表現を使ってみた。
(IPAddressクラスのGetAddressBytes()なんかでも出来る)

001
002
003
004
005
006

$addrs = "10.2.10.2","10.30.10.3","10.30.10.130","10.210.1.1","10.1.244.2"
$addrs | %{$_ -match '(\d+).(\d+).(\d+).(\d+)' | Out-Null
          1..4 | %{$matches[$_] = [int]$matches[$_]
}
          
New-Object PsObject -Property $matches} |
 
          
sort {$_."1",$_."2",$_."3",$_."4"
          } | select @{name="IPAddress";expression={$_."0"}}

こんな感じで良いのかと思ったのだが結果を見るとうまくいっていない。プロパティが文字列として扱われている。$matchesを直接プロパティに設定したのではダメっぽい(理由は今ひとつ分かっていないが)

仕方が無いのでプロパティを一つずつ設定することにした。

001
002
003
004
005
006
007

$addrs = "10.2.10.2","10.30.10.3","10.30.10.130","10.210.1.1","10.1.244.2"
$addrs | %{$_ -match '(\d+).(\d+).(\d+).(\d+)' | Out-Null
            1..4 | %{$matches[$_] = [int]$matches[$_]
}
           
0..4 | %{$props=@{}}{$props."p$($_)" = $Matches[$_]
}
            
New-Object PsObject -Property $props
          } |
 
          
sort p1,p2,p3,p4 | select @{name="IPAddress";expression={$_.p0}}

20110203190630

今度は良さそうだ。

次は考え方を変えて文字列のままソートしてみる。
文字列の場合はそれぞれのオクテットの桁数を3桁に揃えてやれば良いだろう。

001
002
003
004

$addrs = "10.2.10.2","10.30.10.3","10.30.10.130","10.210.1.1","10.1.244.2"
$addrs |  %{"{0:000}.{1:000}.{2:000}.{3:000}" -f
@([int[]]$_.split('.'))} |
sort | %{"{0}.{1}.{2}.{3}" -f @([int[]]$_.split('.'))}

こっちのほうがいくらかスマートかな?

調べていたら、もっと簡単な方法もあった。
若干裏技的な気もするが、Versionクラスにキャストしてソートすると簡単だ。

001
002

$addrs = "10.2.10.2","10.30.10.3","10.30.10.130","10.210.1.1","10.1.244.2"
$addrs | % { [Version] $_ } | Sort | % { $_.toString() }

だいぶスマートになった。

0 件のコメント:

コメントを投稿