Sign in to follow this  
Followers 0
notta

Could this be done more efficiently?

3 posts in this topic

#1 ·  Posted (edited)

Hey guys, I have to create a comma separated string of IP addresses. The string could easily just consist of each IP address, but I want to create ranges to cut down the size of the string. What I mean by that is:

192.168.1.1,192.168.1.2,192.168.1.3,192.168.1.4,192.168.1.5,192.168.1.6
Want to return 192.168.1.1-192.168.1.6

It was more difficult then I thought it would be, but to be honest I'm curious if this could be done more efficiently? I don't like the fact that I'm treating the IP's as strings. I hate the fact that I had to add the leading 0's to sort the array. If I didn't add the leading 0's the array wouldn't be sorted correctly.

I put together this small example so you guys could see. I will be dealing with 2000+ IP addresses when I actually go to use this. Any feedback would be appreciated.

#include 

Global $aIP = StringSplit("192.168.121.12,192.168.120.176,192.168.134.23,192.168.134.32,192.168.134.67" & _
                   ",192.168.120.177,192.168.121.18,192.168.134.87,172.16.21.35,192.168.121.13,192.168.120.178" & _
                   ",192.168.121.1,192.168.121.2,192.168.120.179,192.168.121.10,172.16.33.2,192.168.121.11,192.168.120.180", ",")

;sequences 192.168.120.176,192.168.120.177,192.168.120.178,192.168.120.179,192.168.120.180
;sequences 192.168.121.1,192.168.121.2
;sequences 192.168.121.10,192.168.121.11,192.168.121.12,192.168.121.13

Global $newArray[UBound($aIP)][2]
$newArray[0][0] = UBound($aIP) - 1
Global $aSequence[1]
$aSequence[0] = 0

;add the leading 0's for sorting purposes
#Region add leading 0's
for $i = 1 To UBound($aIP) - 1
    $split = StringSplit($aIP[$i], ".")

    $newIP = ""
    For $j = 1 To UBound($split) - 1
        Select
            Case $split[$j] > 0 AND $split[$j] <= 9
                $val = "00" & $split[$j]
                $newIP &= $val & "."
            Case $split[$j] >= 10 AND $split[$j] <=99
                $val = "0" & $split[$j]
                $newIP &= $val & "."
            Case $split[$j] >= 100 AND $split[$j] <=255
                $val = $split[$j]
                $newIP &= $val & "."
            Case Else
                MsgBox(16,"","Should never get here")
                Exit
        EndSelect
    Next

    $newIP = StringTrimRight($newIP, 1)
    $newArray[$i][0] = $aIP[$i]
    $newArray[$i][1] = $newIP
Next
#EndRegion add leading 0's

_ArraySort($aIP, 0, 1, 0, 2)
_ArraySort($newArray, 0, 0, 0, 1)


_ArrayDisplay($aIP, "source array sorted")
_ArrayDisplay($newArray, "working array, sorted, with leading 0's")

;delete original array
$aIP = ""

;hold the final string of IP's
$stringOfIP = ""
;array loop counter
$i = 1
;holds the count of how many IP's currently exist in a sequence
$counter = 1
;holds the element of the first element in a sequence to be compared against
$compareVal = 0

If $newArray[0][0] > 1 Then
    Do
        If $counter > 1 Then ;if we are in a sequence run
            If StringLeft($newArray[$i + 1][1], 12) = StringLeft($newArray[$i][1], 12) Then ;check if first 3 octets are equal
                If (StringRight($newArray[$i + 1][1], 3) - $counter) = StringRight($newArray[$compareVal][1], 3) Then ;compare current IP against first IP in the sequence
                    ReDim $aSequence[UBound($aSequence) + 1]
                    $aSequence[0] += 1
                    $aSequence[UBound($aSequence) - 1] = $newArray[$i + 1][0] ;add the IP without the leading 0's
                    $counter += 1
                    $i += 1
                    _ArrayDisplay($aSequence, "In Sequence")
                    ContinueLoop
                EndIf
            EndIf

            ;write out IP's to the string. No sense creating a range for 2 IP's. Only create an IP range for sequence of IP's > 2
            Select
                Case $counter = 2
                    for $j = 1 To $aSequence[0]
                        $stringOfIP &= $aSequence[$j] & ","
                    Next
                Case $counter > 2
                    $stringOfIP &= $aSequence[1] & "-" & $aSequence[UBound($aSequence) -1] & ","
            EndSelect

            ;sequence over. reset variables
            $compareVal = 0
            $counter = 1
            ReDim $aSequence[1]
            $aSequence[0] = 0
            $i += 1
        Else ;not in a sequence. fresh start; this checks and creates the starting sequence array. Will only be here the first time during the sequence
            If StringLeft($newArray[$i][1], 12) = StringLeft($newArray[$i + 1][1], 12) Then ;check if first 3 octets are equal
                If (StringRight($newArray[$i + 1][1], 3) - $counter) = StringRight($newArray[$i][1], 3) Then
                    $compareVal = $i
                    $counter += 1
                    for $j = 0 To $counter - 1
                        ReDim $aSequence[UBound($aSequence) + 1]
                        $aSequence[0] += 1

                        $aSequence[UBound($aSequence) - 1] = $newArray[$i + $j][0]
                        _ArrayDisplay($aSequence, "first 2 elements of sequence")
                    Next
                    $i += 1
                    ContinueLoop
                EndIf
            EndIf

            ;will only get here when the current 2 array elements are not a sequence
            $stringOfIP &= $newArray[$i][0] & ","
            ;reset variables
            $counter = 1
            $i += 1
            $compareVal = 0
        EndIf
    Until ($newArray[0][0] - 1) < $i
Else
    MsgBox(0,"","No IP's found")
    Exit
EndIf

If StringRight($stringOfIP, 1) = "," Then
    $stringOfIP = StringTrimRight($stringOfIP, 1)
EndIf

MsgBox(0,"Final Result",$stringOfIP)
Edited by notta

Share this post


Link to post
Share on other sites



I had a little play with your script, and came up with this.

Hope it helps.

#include <Array.au3>

Local $stringOfIP
Global $aIP = StringSplit("192.168.121.12,192.168.120.176,192.168.134.23,192.168.134.32,192.168.134.67" & _
        ",192.168.120.177,192.168.121.18,192.168.134.87,172.16.21.35,192.168.121.13,192.168.120.178" & _
        ",192.168.121.1,192.168.121.2,192.168.120.179,192.168.121.10,172.16.33.2,192.168.121.11,192.168.120.180", ",", 2)

;sequences 192.168.120.176,192.168.120.177,192.168.120.178,192.168.120.179,192.168.120.180
;sequences 192.168.121.1,192.168.121.2
;sequences 192.168.121.10,192.168.121.11,192.168.121.12,192.168.121.13

#region add leading 0's
For $i = 0 To UBound($aIP) - 1
    $aIP[$i] = Execute(StringRegExpReplace($aIP[$i], "(\d+)\.(\d+)\.(\d+)\.(\d+)", _
            'StringRight("00" & "\1",3) & StringRight("00" & "\2",3) & StringRight("00" & "\3",3) & StringRight("00" & "\4",3)'))
Next
#endregion add leading 0's

_ArrayDisplay($aIP, "Unsorted")
_ArraySort($aIP, 0, 0, 0, 0)
_ArrayDisplay($aIP, "Sorted")

For $i = 0 To UBound($aIP) - 1
    If $i < UBound($aIP) - 2 And $aIP[$i] + 2 = $aIP[$i + 2] Then
        $stringOfIP &= Execute(StringRegExpReplace($aIP[$i], "(.{3})(.{3})(.{3})(.{3})", _
                'number(\1) & "." & number(\2) & "." & number(\3) & "." & number(\4)')) & "-"
        $i += 2
        Do
            If $i < UBound($aIP) - 1 Then $i += 1
            ;ConsoleWrite($aIP[$i] - 1  & "  " & $aIP[$i - 1] & $i & @CRLF)
        Until $i >= UBound($aIP) - 1 Or $aIP[$i] - 1 <> $aIP[$i - 1]
        If $i <> UBound($aIP) - 1 Then $i -= 1
    EndIf

    ; Remove the added zeros
    $stringOfIP &= Execute(StringRegExpReplace($aIP[$i], "(.{3})(.{3})(.{3})(.{3})", _
            'number(\1) & "." & number(\2) & "." & number(\3) & "." & number(\4)')) & ","
Next

;ConsoleWrite(StringTrimRight($stringOfIP, 1) & @CRLF)
MsgBox(0, "Final Result", StringTrimRight($stringOfIP, 1))

Share this post


Link to post
Share on other sites

Wow, Malkey that really streamlined it. I really appreciate you taking the time to do that.

I was swamped all day at work today so I couldn't post. Regular expressions are killer for me, but I'm going to sit down now and go through how you did this. Thanks again.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0