You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi含文本与数字的字符串排序:TObjectList转TArray<String>实现

含文本与数字字符串的自然排序实现(Delphi Pascal)

排序差异对比

普通文本排序按字符ASCII值逐位比较,会导致数字部分排序不符合直觉;自然排序则将数字视为整体按数值比较,两者差异如下:

待排序的含文本与数字的字符串列表普通文本排序结果预期自然排序结果
Team 1Team 1Team 1
Team 2Team 10Team 2
Team 10Team 12Team 10
Team 12Team 2Team 12
Team 20Team 20Team 20
Team 21Team 21Team 21

这类字符串可能是Team X或T101等格式,以下是基于TArray<String>机制实现TSARPanelList自然排序的方案:


核心自然排序比较函数

先实现通用的自然排序比较函数,将字符串拆分为文本段和数字段分别对比:

function NaturalCompare(const S1, S2: string): Integer;
var
  P1, P2: Integer;
  Num1, Num2: Int64;
  function ExtractNextToken(const S: string; var Pos: Integer; out IsNumber: Boolean): string;
  begin
    Result := '';
    if Pos > Length(S) then Exit;
    IsNumber := CharInSet(S[Pos], ['0'..'9']);
    while (Pos <= Length(S)) and (CharInSet(S[Pos], ['0'..'9']) = IsNumber) do
    begin
      Result := Result + S[Pos];
      Inc(Pos);
    end;
  end;
begin
  P1 := 1;
  P2 := 1;
  while (P1 <= Length(S1)) and (P2 <= Length(S2)) do
  begin
    var Token1, Token2: string;
    var IsNum1, IsNum2: Boolean;
    Token1 := ExtractNextToken(S1, P1, IsNum1);
    Token2 := ExtractNextToken(S2, P2, IsNum2);
    if IsNum1 and IsNum2 then
    begin
      Num1 := StrToInt64Def(Token1, 0);
      Num2 := StrToInt64Def(Token2, 0);
      Result := CompareValue(Num1, Num2);
      if Result <> 0 then Exit;
    end
    else
    begin
      Result := CompareText(Token1, Token2);
      if Result <> 0 then Exit;
    end;
  end;
  Result := Length(S1) - Length(S2);
end;

基于TArray的TSARPanelList排序实现

方法一:提取RefName数组排序后重构列表

适配所有支持TArray的Delphi版本:

procedure SortSARPanelListByNaturalName(var SARPanelList: TSARPanelList);
var
  I: Integer;
  Names: TArray<string>;
  SortedIndices: TArray<Integer>;
  TempList: TSARPanelList;
begin
  if SARPanelList.Count = 0 then Exit;

  // 提取所有RefName并保留原始索引
  SetLength(Names, SARPanelList.Count);
  SetLength(SortedIndices, SARPanelList.Count);
  for I := 0 to SARPanelList.Count - 1 do
  begin
    Names[I] := SARPanelList[I].RefName;
    SortedIndices[I] := I;
  end;

  // 对索引数组执行自然排序
  TArray.Sort<Integer>(SortedIndices,
    function(const A, B: Integer): Integer
    begin
      Result := NaturalCompare(Names[A], Names[B]);
    end);

  // 根据排序后的索引重新组织列表
  TempList := TSARPanelList.Create(False); // 不接管对象所有权
  try
    for I := 0 to High(SortedIndices) do
      TempList.Add(SARPanelList[SortedIndices[I]]);
    
    SARPanelList.Clear;
    for I := 0 to TempList.Count - 1 do
      SARPanelList.Add(TempList[I]);
  finally
    TempList.Free;
  end;
end;

方法二:直接对TSARPanel对象数组排序

适合Delphi 2010及以上支持泛型TArray.Sort<T>的版本,代码更简洁:

procedure SortSARPanelListByNaturalName(var SARPanelList: TSARPanelList);
var
  PanelArray: TArray<TSARPanel>;
begin
  if SARPanelList.Count = 0 then Exit;

  // 将列表转换为泛型对象数组
  SetLength(PanelArray, SARPanelList.Count);
  for var I := 0 to SARPanelList.Count - 1 do
    PanelArray[I] := SARPanelList[I];

  // 用自然排序逻辑对对象数组排序
  TArray.Sort<TSARPanel>(PanelArray,
    function(const A, B: TSARPanel): Integer
    begin
      Result := NaturalCompare(A.RefName, B.RefName);
    end);

  // 替换原列表内容
  SARPanelList.Clear;
  for var Panel in PanelArray do
    SARPanelList.Add(Panel);
end;

关键说明

  • NaturalCompare函数自动识别文本/数字段,文本段不区分大小写比较,数字段按数值大小对比,适配Team X、T101等多种格式。
  • 两种实现都基于Delphi内置的TArray.Sort机制,无需手动实现排序算法,仅需提供自定义比较逻辑。
  • 方法二中的匿名函数直接关联TSARPanel的RefName字段,无需额外提取字符串数组,代码更简洁。

内容的提问来源于stack exchange,提问作者Bart Kindt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 14:02:07