定义“正确”。
i18n排序完全取决于您的语言环境。
所以我完全同意PA的观点,这不是一个错误:默认的排序行为按照设计允许 i18n 正常工作。
就像Gerry提到的那样,TStringList.Sort使用AnsiCompareStr和AnsiCompareText(我将在几行中解释它是如何做到的)。
但是: TStringList 是灵活的,它包含Sort、CustomSort和CompareStrings,它们都是虚拟的(因此您可以在后代类中覆盖它们)
此外,当您调用CustomSort时,您可以插入自己的Compare函数。
在这个答案中是一个比较函数,它可以满足你的需求:
- 区分大小写
- 不使用任何语言环境
- 只需比较字符串字符的序数值
CustomSort定义如下:
procedure TStringList.CustomSort(Compare: TStringListSortCompare);
begin
if not Sorted and (FCount > 1) then
begin
Changing;
QuickSort(0, FCount - 1, Compare);
Changed;
end;
end;
默认情况下,Sort方法有一个非常简单的实现,传递一个名为StringListCompareStrings的默认比较函数:
procedure TStringList.Sort;
begin
CustomSort(StringListCompareStrings);
end;
因此,如果您定义自己的TStringListSortCompare兼容的比较方法,那么您可以定义自己的排序。
TStringListSortCompare 被定义为一个全局函数,它采用 TStringList 和两个索引来引用您要比较的项目:
type
TStringListSortCompare = function(List: TStringList; Index1, Index2: Integer): Integer;
您可以使用StringListCompareStrings作为实现自己的指南:
function StringListCompareStrings(List: TStringList; Index1, Index2: Integer): Integer;
begin
Result := List.CompareStrings(List.FList^[Index1].FString,
List.FList^[Index2].FString);
end;
因此,默认情况下 TStringList.Sort 遵循 TList.CompareStrings:
function TStringList.CompareStrings(const S1, S2: string): Integer;
begin
if CaseSensitive then
Result := AnsiCompareStr(S1, S2)
else
Result := AnsiCompareText(S1, S2);
end;
然后使用带有默认用户语言环境 LOCALE_USER_DEFAULT 的底层Windows API 函数CompareString:
function AnsiCompareStr(const S1, S2: string): Integer;
begin
Result := CompareString(LOCALE_USER_DEFAULT, 0, PChar(S1), Length(S1),
PChar(S2), Length(S2)) - 2;
end;
function AnsiCompareText(const S1, S2: string): Integer;
begin
Result := CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, PChar(S1),
Length(S1), PChar(S2), Length(S2)) - 2;
end;
最后是您需要的比较功能。再次限制:
- 区分大小写
- 不使用任何语言环境
- 只需比较字符串字符的序数值
这是代码:
function StringListCompareStringsByOrdinalCharacterValue(List: TStringList; Index1, Index2: Integer): Integer;
var
First: string;
Second: string;
begin
First := List[Index1];
Second := List[Index2];
if List.CaseSensitive then
Result := CompareStr(First, Second)
else
Result := CompareText(First, Second);
end;
Delphi 不是封闭的,恰恰相反:它通常是一个非常灵活的架构。
通常只是一点点挖掘,看看你可以在哪里获得这种灵活性。
——杰伦