sortingdelphinatural-sort

Delphi sorting Strings containing text and numbers


I am trying to sort a list of
strings with text and numbers:
Normal text
sorting goes like:
But I want:
Team 1 Team 1 Team 1
Team 2 Team 10 Team 2
Team 10 Team 12 Team 10
Team 12 Team 2 Team 12
Team 20 Team 20 Team 20
Team 21 Team 21 Team 21

These are user-entered strings, could also be T101, T102, T301 etc. (these could be easier). I don't want to try to reinvent the wheel, but I have not been able to find a Pascal example which does the job.

More details: The items I need to sort are in fact in a TObjectList, which has to be sorted by TSARPanel.RefName:

TSARPanel = class(TObject)
  ...
  RefName: String;
  ...
end;

TSARPanelList = class(TObjectList)
private
  function GetRecord(AIndex: Integer): TSARPanel;
  procedure SetRecord(AIndex: Integer; const AValue: TSARPanel);
public
  property Items[AIndex: Integer]: TSARPanel read GetRecord write SetRecord; default;
  ...
end;

Based on Remy's example, how do I manage to convert it into a TArray<String> based sort?


Solution

  • If you are on a more recent Delphi version, you can make use of TStringHelper.Compare() and the coDigitAsNumbers option. This example is using Delphi 12:

    uses
      System.SysUtils,
      System.Generics.Collections,
      System.Generics.Defaults;
    
    procedure Main;
    begin
      var arr := TArray<string>.Create('Team 1', 'Team 10', 'Team 12', 'Team 2', 'Team 20', 'Team 21');
      TArray.Sort<string>(arr, TDelegatedComparer<string>.Create(
        function(const Left, Right: string): Integer
        begin
          Result := string.Compare(Left, Right, [coDigitAsNumbers]);
        end
        ));
      for var S in arr do
        Writeln(S);
    end;
    

    Update: Based on your question update, a solution for your case could be like this:

      SARPanelList.SortList(
        function (Item1, Item2: Pointer): Integer
        begin
          Result := string.Compare(TSARPanel(Item1).RefName, TSARPanel(Item2).RefName);
        end
      );