1

Unfortunately I have a problem with my code. Over the months I have added a few things to my program every now and then. Now the code is a bit "misbuild(t)" and I need your help. I have a program in which there are threads and posts – like in a classic Internet forum. A thread can contain multiple posts; a posting contains several images and texts. So... You can click on a certain posting in the ListBox and display its images as large as possible. This is done with a separate form. With 3 different radio buttons I can sort it according to the size of the images (megapixel), or according to the modification date, or according to the file name. To be able to sort by megapixel, I once created an class Bildeigenschaften (image properties class). The sorted_List is therefore a List(of Bildeigenschaften). Today, I discovered that sorting by name is unlike sorting by name in Windows Explorer. Windows Explorer sorts Natural (as I found out), so this is how it is

ABC9

ABC10

instead of like in my program

ABC10

ABC9

. So I got some code that sorts "Natural". How do I get this linked now?

the Form

Private Property List_of_class_Bildeigenschaften As New List(Of Bildeigenschaften)
   
    Private sorted_List As List(Of Bildeigenschaften)
'--------------------
Private Sub RadioButton2_CheckedChanged(sender As Object, e As EventArgs) Handles RadioButton2.CheckedChanged
        If RadioButton2.Checked Then
            sorted_List = List_of_class_Bildeigenschaften.OrderBy(Function(o) o._FileInfo.Name).ToList()
            If CheckBox1.Checked Then
                sorted_List.Reverse()
            End If
        End If

        If CheckBox1.Checked Then
            sorted_List.Reverse()
        End If
    End Sub
'--------------------
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 As Integer = 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

Class Bildeigenschaften

Public NotInheritable Class Bildeigenschaften
    Public Megapixels As UInt32
    Public Bild As System.Drawing.Bitmap
    Public _FileInfo As IO.FileInfo

    Public Sub New(ByVal Breite As UInt32, ByVal Hoehe As UInt32, ByVal Bild As Bitmap, ByVal einefileinfo As IO.FileInfo)
        Me.Megapixels = Breite * Hoehe
        Me.Bild = Bild
        Me._FileInfo = einefileinfo
    End Sub
End Class

enter image description here

Thus, my problem is not similar to this.

Daniel
  • 374
  • 1
  • 12
  • Does this answer your question? [Natural Sort Order in C#](https://stackoverflow.com/questions/248603/natural-sort-order-in-c-sharp) – GSerg Jan 08 '22 at 13:36
  • @GSerg It's one of the many things I've found. But I have a List(of Class) and I can't just write `sorted_List.Sort (new NaturalComparer)`. Do you understand what I mean? – Daniel Jan 08 '22 at 13:48
  • Then make your `NaturalComparer` `Implements IComparer(Of Class)`, and look at the respective property in `Compare()`. – GSerg Jan 08 '22 at 17:13

1 Answers1

3

You can use Windows' StrCmpLogicalW that is also used by the explorer:

Public Class NaturalSortComparer
    Implements IComparer(Of String)

    Declare Unicode Function StrCmpLogicalW Lib "shlwapi.dll" ( _
        ByVal s1 As String, _
        ByVal s2 As String) As Int32

    Public Function Compare(ByVal x As String, ByVal y As String) As Integer Implements System.Collections.Generic.IComparer(Of String).Compare
        Return StrCmpLogicalW(x, y)
    End Function

End Class

For example:

Dim list = New List(Of String)
list.Add("ABC10")
list.Add("ABC9")
Console.WriteLine(String.Join(",", list))
list.Sort(New NaturalSortComparer())
Console.WriteLine(String.Join(",", list))

Output:

ABC10,ABC9
ABC9,ABC10

You can also use it with LINQ:

list = list.OrderBy(Function(s) s, New NaturalSortComparer()).ToList()

That answers also your question how to install your comparer in the query:

sorted_List = List_of_class_Bildeigenschaften.OrderBy(Function(o) o._FileInfo.Name, New NaturalComparer()).ToList()
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • 2
    @AndrewMorton: Yes, i just edited my answer to show that, the very last approach – Tim Schmelter Jan 08 '22 at 15:30
  • Tim and @AndrewMorton Thanks very much! That's working. I appreciate that. `sorted_List = List_of_class_Bildeigenschaften.OrderBy(Function(o) o._FileInfo.Name, New NaturalSortComparer()).ToList()` – Daniel Jan 08 '22 at 15:32