Sign in to follow this  
Followers 0
PeteW

UDF : _StringCompareVersions()

7 posts in this topic

#1 ·  Posted (edited)

Updated 12/07/05: Following Valik's advice...

Returns -1,0,1 for older, same, newer versions.

@error is set to 1,2,3 if 1st, 2nd or both strings being compared are of the wrong format.

~~~

Initially written for use in SvenP's MSPatch 'Using AutoIT to deploy patches...' http://www.autoitscript.com/forum/index.php?showtopic=7719.

In some cases, when testing whether a patch is installed, FileGetVersion() string values are compared.

Comparing numeric strings using standard operators doesn't always give results you might expect - e.g. "9" is not less than "10".

The _StringCompareVersions() function below compares 2 strings, expected to be of the FileGetVersion format [a.b.c.d]

BTW, there are many KiXtart UDFs posted at http://www.scriptlogic.com/kixtart/functio...nctionlist.aspx - although it's another scripting language, it maybe similar enough to allow easy conversion to AutoIt(?).

Cheers,

Pete.

Function:

;===============================================================================
;
; FunctionName:  _StringCompareVersions()
; Description:    Compare 2 strings of the FileGetVersion format [a.b.c.d].
; Syntax:          _StringCompareVersions( $s_Version1, [$s_Version2] )
; Parameter(s):  $s_Version1          - The string being compared
;                  $s_Version2        - The string to compare against
;                                         [Optional] : Default = 0.0.0.0
; Requirement(s):   None
; Return Value(s):  0 - Strings are the same (if @error=0)
;                 -1 - First string is (<) older than second string
;                  1 - First string is (>) newer than second string
;                  0 and @error<>0 - String(s) are of incorrect format:
;                        @error 1 = 1st string; 2 = 2nd string; 3 = both strings.
; Author(s):        PeteW
; Note(s):        Comparison checks that both strings contain numeric (decimal) data.
;                  Supplied strings are contracted or expanded (with 0s)
;                    MostSignificant_Major.MostSignificant_minor.LeastSignificant_major.LeastSignificant_Minor
;
;===============================================================================

Func _StringCompareVersions($s_Version1, $s_Version2 = "0.0.0.0")
    
; Confirm strings are of correct basic format. Set @error to 1,2 or 3 if not.
    SetError((StringIsDigit(StringReplace($s_Version1, ".", ""))=0) + 2 * (StringIsDigit(StringReplace($s_Version2, ".", ""))=0))
    If @error>0 Then Return 0; Ought to Return something!

    Local $i_Index, $i_Result, $ai_Version1, $ai_Version2

; Split into arrays by the "." separator
    $ai_Version1 = StringSplit($s_Version1, ".")
    $ai_Version2 = StringSplit($s_Version2, ".")
    $i_Result = 0; Assume strings are equal
    
; Ensure strings are of the same (correct) format:
;  Short strings are padded with 0s. Extraneous components of long strings are ignored. Values are Int.
    If $ai_Version1[0] <> 4 Then ReDim $ai_Version1[5]
    For $i_Index = 1 To 4
        $ai_Version1[$i_Index] = Int($ai_Version1[$i_Index])
    Next

    If $ai_Version2[0] <> 4 Then ReDim $ai_Version2[5]
    For $i_Index = 1 To 4
        $ai_Version2[$i_Index] = Int($ai_Version2[$i_Index])
    Next

    For $i_Index = 1 To 4
        If $ai_Version1[$i_Index] < $ai_Version2[$i_Index] Then; Version1 older than Version2
            $i_Result = -1
        ElseIf $ai_Version1[$i_Index] > $ai_Version2[$i_Index] Then; Version1 newer than Version2
            $i_Result = 1
        EndIf
   ; Bail-out if they're not equal
        If $i_Result <> 0 Then ExitLoop
    Next

    Return $i_Result

EndFunc ;==>_StringCompareVersions

Examples:

; Example to demonstrate problem with a standard operator string compare:
; s_Ver1 is reported as newer than s_Ver2, result=3
$s_Ver1 = "9.0.0.0"
$s_Ver2 = "10.0.0.0"

If $s_Ver1 = $s_Ver2 Then $i_Result = 0
If $s_Ver1 < $s_Ver2 Then $i_Result = -1
If $s_Ver1 > $s_Ver2 Then $i_Result = 1
MsgBox(0, "String comparison", $s_Ver1 & " vs " & $s_Ver2 & " result: " & $i_Result)

; _StringCompareVersions() comparison of the same strings:
; s_Ver1 is reported as older than s_Ver2 (as expected), result=2
$i_Result = _StringCompareVersions($s_Ver1, $s_Ver2)
MsgBox(0, "_StringCompareVersions", "(" & $s_Ver1 & "," & $s_Ver2 & ") result: " & $i_Result)

; _StringCompareVersions() comparison of 0.0.0.0 against 'nothing' shows default of 0.0.0.0 is used:
; s_Ver1 is reported as the same (as expected), result=1
;  NB FileGetVersion(file) returns 0.0.0.0 when 'file' is not found (or other error).
$s_Ver1 = "0.0.0.0"
$i_Result = _StringCompareVersions($s_Ver1)
MsgBox(0, "_StringCompareVersions", "(" & $s_Ver1 & ") result: " & $i_Result)

$s_Ver1 = "WrongFormat"
$i_Result = _StringCompareVersions($s_Ver1, $s_Ver2)
MsgBox(0, "_StringCompareVersions", "(" & $s_Ver1 & "," & $s_Ver2 & ") result: " & $i_Result & " " &@error)
Edited by PeteW

Share this post


Link to post
Share on other sites



Your return values could use some work. Its common convention in programming to have the following return values on a comparison function:

  • 0 - Both arguments are the same.
  • 1 - The first argument is greater than the second.
  • -1 - The second argument is greater than the first.

Share this post


Link to post
Share on other sites

Hi valik,

Thanks for the suggestion re: Return values.

I'd decided on those type of return values after checking out 'Version Checking of Redistributable Files':

http://msdn.microsoft.com/library/default....utableFiles.asp

I can now see it makes sense to have -1,0,1 - even though the function will now return (the same value as) False when the strings are the same.

I've a question re: my 'Error' Return code (0). Does the convention suggest a return code for such cases?

Cheers,

Pete.

Share this post


Link to post
Share on other sites

You could always fall back on a lexicographical comparison of the two strings in the event that they do not contain the same number of segments. You might also set the @extended or @error flag so that the user can check to make sure the two versions were "proper" in case that is important. That doesn't cause the need for another error return value, still returns some-what valid results and still offers the ability to ensure the comparison is correct.

Share this post


Link to post
Share on other sites

I'm sorry if this is a basic question, but I'm new to AutoIt. How would I use this code in other scripts without having to copy/paste it everytime?

Thank you in advance.

You could always fall back on a lexicographical comparison of the two strings in the event that they do not contain the same number of segments. You might also set the @extended or @error flag so that the user can check to make sure the two versions were "proper" in case that is important. That doesn't cause the need for another error return value, still returns some-what valid results and still offers the ability to ensure the comparison is correct.

Share this post


Link to post
Share on other sites

SciTe has a Snippet holder made by gafrost or you could put it in an #include <thsfile.au3> in your include folder and just use #include <thisfile.au3> in the scripts you want to use it in.


Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Share this post


Link to post
Share on other sites

(both) Worked nice. Thank you.

SciTe has a Snippet holder made by gafrost or you could put it in an #include <thsfile.au3> in your include folder and just use #include <thisfile.au3> in the scripts you want to use it in.

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