Delphi含文本与数字的字符串排序:TObjectList转TArray<String>实现
含文本与数字字符串的自然排序实现(Delphi Pascal)
排序差异对比
普通文本排序按字符ASCII值逐位比较,会导致数字部分排序不符合直觉;自然排序则将数字视为整体按数值比较,两者差异如下:
| 待排序的含文本与数字的字符串列表 | 普通文本排序结果 | 预期自然排序结果 |
|---|---|---|
| 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 |
这类字符串可能是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
相关产品推荐
相关产品推荐

