; #FUNCTION# ;=============================================================================== ; ; Name...........: _NaturalCompare ; Description ...: Compare two strings using Natural (Alphabetical) sorting. ; Syntax.........: _NaturalCompare($s1, $s2, $iCase = 0) ; Parameters ....: $s1, $s2 - Strings to compare ; $iCase - Case sensitive or insensitive comparison ; |0 - Case insensitive (default) ; |1 - Case sensitive ; Return values .: Success - One of the following: ; |0 - Strings are equal ; |-1 - $s1 comes before $s2 ; |1 - $s1 goes after $s2 ; Failure - Returns -2 and Sets @Error: ; |1 - $s1 or $s2 is not a string ; |2 - $iCase is invalid ; Author ........: Erik Pilsits ; Modified.......: ; Remarks .......: Original algorithm by Dave Koelle ; Related .......: StringCompare ; Link ..........: http://www.davekoelle.com/alphanum.html ; Example .......: Yes ; ; ;========================================================================================== Func _NaturalCompare($s1, $s2, $iCase = 0) If (Not IsString($s1)) Or (Not IsString($s2)) Then Return SetError(1, 0, -2) If $iCase <> 0 And $iCase <> 1 Then Return SetError(2, 0, -2) Local $n = 0, $iLen = 1 Local $s1chunk, $s2chunk While $n = 0 ; get next chunk ; STRING 1 $iLen = 1 If StringIsDigit(StringLeft($s1, 1)) Then ; chunk of digits For $i = 2 To StringLen($s1) If StringIsDigit(StringMid($s1, $i, 1)) Then $iLen += 1 Else ExitLoop EndIf Next Else ; chunk of letters For $i = 2 To StringLen($s1) If Not StringIsDigit(StringMid($s1, $i, 1)) Then $iLen += 1 Else ExitLoop EndIf Next EndIf $s1chunk = StringLeft($s1, $iLen) ; STRING 2 $iLen = 1 If StringIsDigit(StringLeft($s2, 1)) Then ; chunk of digits For $i = 2 To StringLen($s2) If StringIsDigit(StringMid($s2, $i, 1)) Then $iLen += 1 Else ExitLoop EndIf Next Else ; chunk of letters For $i = 2 To StringLen($s2) If Not StringIsDigit(StringMid($s2, $i, 1)) Then $iLen += 1 Else ExitLoop EndIf Next EndIf $s2chunk = StringLeft($s2, $iLen) ; ran out of chunks, strings are the same, return 0 If $s1chunk = "" And $s2chunk = "" Then Return 0 ; remove chunks from strings $s1 = StringMid($s1, StringLen($s1chunk) + 1) $s2 = StringMid($s2, StringLen($s2chunk) + 1) ; Case 1: both chunks contain letters If (Not StringIsDigit($s1chunk)) And (Not StringIsDigit($s2chunk)) Then $n = StringCompare($s1chunk, $s2chunk, $iCase) Else ; Case 2: both chunks contain numbers If StringIsDigit($s1chunk) And StringIsDigit($s2chunk) Then Local $i1chunk = Int($s1chunk) Local $i2chunk = Int($s2chunk) If $i1chunk > $i2chunk Then Return 1 ElseIf $i1chunk < $i2chunk Then Return -1 EndIf Else ; Case 3: one chunk has letters, the other has numbers; or one is empty ; if we get here, this should be the last and deciding test, so return the result Return StringCompare($s1chunk, $s2chunk, $iCase) EndIf EndIf WEnd Return $n EndFunc