You'll need to have a Natural Comparison of the strings to get what you're looking for.
Here's a couple of options.
vb.net Code:
Imports System.Text.RegularExpressions
Public Class NaturalComparer
Implements IComparer(Of String)
Private _pos As Integer
Private ReadOnly _order As Integer
Public Sub New(Optional Ascending As Boolean = True)
_order = If(Ascending, 1, -1)
End Sub
Private Shared Function RegexSplit(ByVal s As String) As String()
Return Regex.Split(s, "(\d+)", RegexOptions.IgnoreCase)
End Function
Private Shared Function GetEmptyStrings() As Predicate(Of String)
Return Function(s) String.IsNullOrEmpty(s)
End Function
Public Function Compare(x As String, y As String) As Integer Implements IComparer(Of String).Compare
Dim left As New List(Of String)(RegexSplit(x))
Dim right As New List(Of String)(RegexSplit(y))
left.RemoveAll(GetEmptyStrings())
right.RemoveAll(GetEmptyStrings())
_pos = 0
For Each x In left
If y.Count > _pos Then
If Not Decimal.TryParse(x, Nothing) AndAlso Not Decimal.TryParse(right(_pos), Nothing) Then
Dim result As Integer = String.Compare(x, right(_pos), True)
If result <> 0 Then
Return result * _order
Else
_pos += 1
End If
ElseIf Decimal.TryParse(x, Nothing) AndAlso Not Decimal.TryParse(right(_pos), Nothing) Then
Return -1 * _order
ElseIf Not Decimal.TryParse(x, Nothing) AndAlso Decimal.TryParse(right(_pos), Nothing) Then
Return 1 * _order
Else
Dim result = Decimal.Compare(Decimal.Parse(x), Decimal.Parse(right(_pos)))
If result = 0 Then
_pos += 1
Else
Return result * _order
End If
End If
Else
Return -1 * _order
End If
Next
Return _order
End Function
End Class
Or using Api Methods.
vb.net Code:
Public Class ApiNaturalComparer
Implements IComparer(Of String)
Private Class NativeMethods
Public Declare Unicode Function StrCmpLogicalW Lib "shlwapi.dll" (s1 As String, s2 As String) As Integer
End Class
Private ReadOnly _order As Integer
Public Sub New(Optional IsAscending As Boolean = True)
_order = If(IsAscending, 1, -1)
End Sub
Public Function Compare(x As String, y As String) As Integer Implements IComparer(Of String).Compare
Return NativeMethods.StrCmpLogicalW(x, y) * _order
End Function
End Class
Usage example of both options.
vb.net Code:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim MyList = New List(Of String)({"ob1", "ob5", "ob2", "ob3", "ob33", "ob10", "ob1", "ob11", "ob123", "ob20"})
'MyList.Sort(New NaturalComparer(True))
'OutputListBox.Items.AddRange(MyList.ToArray())
MyList.Sort(New ApiNaturalComparer(True))
OutputListBox.Items.AddRange(MyList.ToArray())
End Sub
End Class