我从我的排序例程库中获取了以下内容。请忽略我的一些命名约定:)。
经过审核,我注意到我的 CompareNaturalNum() 例程存在问题
“1.01.1.3.1”和“1.01.1.3.1.1”相同。我已经在下面的代码中修复了它,并展示了如何使用它。
QuickSortMultiNaturalNum - 变体数组的快速排序,您可以在其中指定要排序的列。
Public Sub QuickSortMultiNaturalNum(strArray As Variant, intBottom As Long, intTop As Long, intSortIndex As Long, Optional intLowIndex As Long, Optional intHighIndex As Long = -1)
Dim strPivot As String, strTemp As String
Dim intBottomTemp As Long, intTopTemp As Long
Dim i As Long
intBottomTemp = intBottom
intTopTemp = intTop
If intHighIndex < intLowIndex Then
If (intBottomTemp <= intTopTemp) Then
intLowIndex = LBound(strArray, 2)
intHighIndex = UBound(strArray, 2)
End If
End If
strPivot = strArray((intBottom + intTop) \ 2, intSortIndex)
While (intBottomTemp <= intTopTemp)
' < comparison of the values is a descending sort
While (CompareNaturalNum(strArray(intBottomTemp, intSortIndex), strPivot) < 0 And intBottomTemp < intTop)
intBottomTemp = intBottomTemp + 1
Wend
While (CompareNaturalNum(strPivot, strArray(intTopTemp, intSortIndex)) < 0 And intTopTemp > intBottom)
intTopTemp = intTopTemp - 1
Wend
If intBottomTemp < intTopTemp Then
For i = intLowIndex To intHighIndex
strTemp = Var2Str(strArray(intBottomTemp, i))
strArray(intBottomTemp, i) = Var2Str(strArray(intTopTemp, i))
strArray(intTopTemp, i) = strTemp
Next
End If
If intBottomTemp <= intTopTemp Then
intBottomTemp = intBottomTemp + 1
intTopTemp = intTopTemp - 1
End If
Wend
'the function calls itself until everything is in good order
If (intBottom < intTopTemp) Then QuickSortMultiNaturalNum strArray, intBottom, intTopTemp, intSortIndex, intLowIndex, intHighIndex
If (intBottomTemp < intTop) Then QuickSortMultiNaturalNum strArray, intBottomTemp, intTop, intSortIndex, intLowIndex, intHighIndex
End Sub
CompareNaturalNum - 自定义比较功能
Function CompareNaturalNum(string1 As Variant, string2 As Variant) As Long
'string1 is less than string2 -1
'string1 is equal to string2 0
'string1 is greater than string2 1
Dim n1 As Long, n2 As Long
Dim iPosOrig1 As Long, iPosOrig2 As Long
Dim iPos1 As Long, iPos2 As Long
Dim nOffset1 As Long, nOffset2 As Long
If Not (IsNull(string1) Or IsNull(string2)) Then
iPos1 = 1
iPos2 = 1
Do While iPos1 <= Len(string1)
If iPos2 > Len(string2) Then
CompareNaturalNum = 1
Exit Function
End If
If isDigit(string1, iPos1) Then
If Not isDigit(string2, iPos2) Then
CompareNaturalNum = -1
Exit Function
End If
iPosOrig1 = iPos1
iPosOrig2 = iPos2
Do While isDigit(string1, iPos1)
iPos1 = iPos1 + 1
Loop
Do While isDigit(string2, iPos2)
iPos2 = iPos2 + 1
Loop
nOffset1 = (iPos1 - iPosOrig1)
nOffset2 = (iPos2 - iPosOrig2)
n1 = Val(Mid(string1, iPosOrig1, nOffset1))
n2 = Val(Mid(string2, iPosOrig2, nOffset2))
If (n1 < n2) Then
CompareNaturalNum = -1
Exit Function
ElseIf (n1 > n2) Then
CompareNaturalNum = 1
Exit Function
End If
' front padded zeros (put 01 before 1)
If (n1 = n2) Then
If (nOffset1 > nOffset2) Then
CompareNaturalNum = -1
Exit Function
ElseIf (nOffset1 < nOffset2) Then
CompareNaturalNum = 1
Exit Function
End If
End If
ElseIf isDigit(string2, iPos2) Then
CompareNaturalNum = 1
Exit Function
Else
If (Mid(string1, iPos1, 1) < Mid(string2, iPos2, 1)) Then
CompareNaturalNum = -1
Exit Function
ElseIf (Mid(string1, iPos1, 1) > Mid(string2, iPos2, 1)) Then
CompareNaturalNum = 1
Exit Function
End If
iPos1 = iPos1 + 1
iPos2 = iPos2 + 1
End If
Loop
' Everything was the same so far, check if Len(string2) > Len(String1)
' If so, then string1 < string2
If Len(string2) > Len(string1) Then
CompareNaturalNum = -1
Exit Function
End If
Else
If IsNull(string1) And Not IsNull(string2) Then
CompareNaturalNum = -1
Exit Function
ElseIf IsNull(string1) And IsNull(string2) Then
CompareNaturalNum = 0
Exit Function
ElseIf Not IsNull(string1) And IsNull(string2) Then
CompareNaturalNum = 1
Exit Function
End If
End If
End Function
isDigit - 让您知道字符串值是否为数字 (0-9) 的简单函数
Function isDigit(ByVal str As String, pos As Long) As Boolean
Dim iCode As Long
If pos <= Len(str) Then
iCode = Asc(Mid(str, pos, 1))
If iCode >= 48 And iCode <= 57 Then isDigit = True
End If
End Function
Var2Str - 因为它处理变体,值可能是Null,所以将其转换为字符串
Public Function Var2Str(Value As Variant, Optional TrimSpaces As Boolean = True) As String
If IsNull(Value) Then
'Var2Str = vbNullString
Exit Function
End If
If TrimSpaces Then
Var2Str = Trim(Value)
Else
Var2Str = CStr(Value)
End If
End Function
测试 - 这是如何使用它的示例代码。只需更改范围值。对QuickSortMultiNaturalNum 的调用中的最后一个1 是要排序的列(ID 所在的列)。
Sub Test()
Dim Target As Range
Dim vData 'as Variant
Dim Rows As Long
' Set Target to the CurrentRegion of cells around "A1"
Set Target = Range("A1").CurrentRegion
' Copy the values to a variant
vData = Target.Value2
' Get the high/upper limit of the array
Rows = Target.Rows.Count 'UBound(vData, 1)
' Sor The variant array, passing the variant, lower limit, upper limit and the index of the column to be sorted.
QuickSortMultiNaturalNum vData, 1, Rows, 1
' Paste the values back onto the sheet. For testing, you may want to paste it to another sheet/range
Range("A1").Resize(Target.Rows.Count, Target.Columns.Count).Value = vData
End Sub