Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Natural sorting


  • Please log in to reply
21 replies to this topic
Joolee
  • Members
  • 19 posts
  • Last active: Feb 17 2011 02:30 PM
  • Joined: 08 Aug 2005
I just found out that listviews can have natural sorting:
<!-- m -->http://www.autohotke... ... tm#Logical<!-- m -->

I was looking for something else but found this instead :p

A DLL call to StrCmpLogicalW should be the solution to sorting other lists.

animeaime
  • Members
  • 1045 posts
  • Last active: Jun 18 2011 04:44 AM
  • Joined: 04 Nov 2008
I was showed this thread and it is exactly what I was looking for. I tweaked Laszlo's solution from a few posts ago because I need to allow sorting regardless how many numbers are in the string - looking for performance feedback.

LogicalSort(x,y,offset)
{
    static RegEx := "S)(\D*)(\d*)(.*)"
    
    Loop
    {
        RegExMatch(x, RegEx, x)
        RegExMatch(y, RegEx, y)
        
        if (x1 != y1)
            return x1 < y1 ? -1 : 1
            
        if (x2 != y2)
            return x2 < y2 ? -1 : 1
            
        if (x3 = "" || y3 = "")
            break
            
        x := x3
        y := y3
    }

    if (x3 != "")
    {
        ;x is "longer"
        return 1
    }
    else if (y3 != "")
    {
        ;y is "longer"
        return -1
    }
    else
    {
        ;equal - maintain original order (stable)
        return -offset
    }
}

As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.

kenomby
  • Guests
  • Last active:
  • Joined: --

I just found out that listviews can have natural sorting:
http://www.autohotke... ... tm#Logical

A DLL call to StrCmpLogicalW should be the solution to sorting other lists.

how would:
int StrCmpLogicalW( LPCWSTR psz1, LPCWSTR psz2)
http://msdn.microsof.../bb759947(VS.85).aspx
translate to AutoHotkey?

(UPDATE: You could achieve logical sorting in a script by writing a sort algorithm and calling MultiByteToWideChar + StrCmpLogicalW via DllCall (requires Windows XP).
http://www.autohotke...ic9822-30.htmls

how would this work?

HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
Try:
String1=test

String2=test

String3=test1

String4=tesa

String5=x

Loop 5

   VarSetCapacity(wideString%A_Index%, StrLen(String%A_Index%)*2+1,0)

   , DllCall("MultiByteToWideChar", "UInt",0, "UInt",0, "UInt",&String%A_Index%, "Int",-1, "UInt",&wideString%A_Index%, "Int",StrLen(String%A_Index%)+1)

MsgBox % string1 " . " string2 ": " DllCall("Shlwapi.dll\StrCmpLogicalW","Uint",&wideString1,"UInt",&wideString2)

MsgBox % string1 " . " string3 ": " DllCall("Shlwapi.dll\StrCmpLogicalW","Uint",&wideString1,"UInt",&wideString3)

MsgBox % string1 " . " string4 ": " DllCall("Shlwapi.dll\StrCmpLogicalW","Uint",&wideString1,"UInt",&wideString4)

MsgBox % string4 " . " string5 ": " DllCall("Shlwapi.dll\StrCmpLogicalW","Uint",&wideString4,"UInt",&wideString5)


temp01
  • Members
  • 120 posts
  • Last active: May 18 2013 08:27 PM
  • Joined: 09 Jul 2009
Here's a function that you can use with the built-in Sort command (or just pass two strings as parameters):

StrCmpLogical(str1, str2){
	Loop, 2
		MultiByteToWideChar(str%A_Index%)
	return DllCall("ShlWapi\StrCmpLogicalW", "UInt", &str1, "UInt", &str2)
}
MultiByteToWideChar(ByRef str){
	ostr := str, size = 0
	Loop, 2 {
		VarSetCapacity(str, size*2)
		size := DllCall("MultiByteToWideChar", "UInt", 65001, "UInt", 0, "UInt", &ostr, "int", -1, "UInt", &str, "int", size)
	}
}


; Example:
list=
(
1234568
File 1.ahk 
File 20.png 
File 2 
File 3.tmp 
File 9.abc
1234567
)

msgbox Unsorted/Before:`n`n%list%
	Sort, list, F StrCmpLogical
msgbox Sorted/After:`n`n%list%


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
temp01, MultiByteToWideChar requires VarSetCapacity. Without it, it is likely to corrupt the script's memory. For instance,
MultiByteToWideChar(a:="1234567")
MsgBox % VarSetCapacity(a)
This shows 7, which is clearly not enough to hold a unicode string of 7 characters. COM_Unicode4Ansi shows the correct way to do it.

temp01
  • Members
  • 120 posts
  • Last active: May 18 2013 08:27 PM
  • Joined: 09 Jul 2009
Oops, I forgot that. Thanks Lex, I fixed the function above.