Sort strings like Windows Explorer alpha numerically - Natural sort order

I need to sort strings / string list in the same order that Windows Explorer sorts files when sorted by name

The sorting in alphabetical, but numbers are treated as numbers not characters, so “10” comes between “2” and “22”

Examples

TestFile 1 aaa.txt
TestFile 2 bbb.txt
TestFile 10 ccc.txt
TestFile 22 ddd.txt

TestFile 1 (1) aaa.txt
TestFile 1 (2) bbb.txt
TestFile 1 (10) ccc.txt
TestFile 1 (22) ddd.txt

I am mainly concerned about scenarios all have a similar name “TestFile .” but if the solutions also support different files names that would be great - like this:

BlahBlahBlah 1 (1) aaa.txt
BlahBlahBlah 1 (2) bbb.txt
BlahBlahBlah 1 (10) ccc.txt
BlahBlahBlah 1 (22) ddd.txt
TestFile 1 (1) aaa.txt
TestFile 1 (2) bbb.txt
TestFile 1 (10) ccc.txt
TestFile 1 (22) ddd.txt

Any code or tips to do this are appreciated.

1 Like

This is called “natural sort order” and there are a few answers.

http://www.delphigroups.info/2/df/470666.html

1 Like

Brilliant. Thank you Ian

Ive added “Natural sort order” to the title to make it easier to find

2 Likes

Sheesh, ‘Natural’? You’ve got to be joking.

I’d love to be able to turn it off (is there a way?), surely everyone has many examples where it simply makes stuff (very) hard to find?

1 Like

Explorer does a lot of ‘unnatural’ things :joy:

For example, I never try searching for anything with it because I’m getting pretty old now and I don’t think I’ll live long enough for Explorer to find files which match my search criteria in my lifetime.

(I use Everything from Void Tools which shows how quick it could be if Microsoft put some effort into it).

Ironically the reason I knew about Natural Search Order was because a user asked me to implement it on a screen recently despite me arguing there was nothing wrong with the old sort order.

They won, of course, due to the need for money outweighing the need for me to be right. :yum:

I think this is very nice, on Windows at least.

function StrCmpLogicalW(psz1, psz2: PWideChar): Integer; stdcall; external 'shlwapi.dll';

procedure SortStringArray(var StringArray: TArray<string>);
var
    Comparer: IComparer<string>;
begin
    Comparer := TComparer<string>.Construct(
         function(const Left, Right: string): Integer
            begin
               Result := StrCmpLogicalW( PWideChar(Left.ToLower), PWideChar(Right.ToLower) );
            end   
                 );
    TArray.Sort<string>(StringArray, Comparer);     //  Not Case Sensitive with this WinAPI call
end;
1 Like

Hi Scott

This plagues us all.

The only way I’ve found to deal with this is leading zeroes.

01
02
10
22

Of course you have to pad to the highest expected number.

Kind Regards
Michael Lofting