我怎样才能让 TStringList 在 Delphi 中以不同的方式排序 [英] How can I get TStringList to sort differently in Delphi

查看:56
本文介绍了我怎样才能让 TStringList 在 Delphi 中以不同的方式排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的 TStringList.我对它做了一个 TStringList.Sort .

I have a simple TStringList. I do a TStringList.Sort on it.

然后我注意到下划线_"排在大写字母A"之前.这与对相同文本进行排序并在 A 之后排序 _ 的第三方包形成对比.

Then I notice that the underscore "_" sorts before the capital letter "A". This was in contrast to a third party package that was sorting the same text and sorted _ after A.

根据 ANSI 字符集,A-Z 是 65 - 90 的字符,_ 是 95.所以看起来 3rd 方包正在使用该顺序,而 TStringList.Sort 不是.

According to the ANSI character set, A-Z are characters 65 - 90 and _ is 95. So it looks like the 3rd party package is using that order and TStringList.Sort isn't.

我深入研究了 TStringList.Sort 的内部结构,它使用 AnsiCompareStr(区分大小写)或 AnsiCompareText(不区分大小写)进行排序.我尝试了两种方法,将我的 StringList 的 CaseSensitive 值设置为 true,然后设置为 false.但在这两种情况下,_"先排序.

I drilled down into guts of TStringList.Sort and it is sorting using AnsiCompareStr (Case Sensitive) or AnsiCompareText (Case Insensitive). I tried it both ways, setting my StringList's CaseSensitive value to true and then false. But in both cases, the "_" sorts first.

我无法想象这是 TStringList 中的错误.所以这里一定有我没有看到的其他东西.那可能是什么?

I just can't imagine that this is a bug in TStringList. So there must be something else here that I am not seeing. What might that be?

我真正需要知道的是如何让我的 TStringList 进行排序,使其与其他包的顺序相同.

What I really need to know is how can I get my TStringList to sort so that it is in the same order as the other package.

作为参考,我使用的是 Delphi 2009,并且在我的程序中使用了 Unicode 字符串.

For reference, I am using Delphi 2009 and I'm using Unicode strings in my program.

所以这里的最终答案是用你想要的任何东西(例如非 ansi 比较)覆盖 Ansi 比较,如下所示:

So the final answer here is to override the Ansi compares with whatever you want (e.g. non-ansi compares) as follows:

type
  TMyStringList = class(TStringList)
  protected
    function CompareStrings(const S1, S2: string): Integer; override;
  end;

function TMyStringList.CompareStrings(const S1, S2: string): Integer;
begin
  if CaseSensitive then
    Result := CompareStr(S1, S2)
  else
    Result := CompareText(S1, S2);
end;

推荐答案

定义正确".
i18n 排序完全取决于您的语言环境.
所以我完全同意 PA 这不是一个错误:默认的 Sort 行为作为旨在让 i18n 正常工作.

Define "correctly".
i18n sorting totally depends on your locale.
So I totally agree with PA that this is not a bug: the default Sort behaviour works as designed to allow i18n to work properly.

就像 Gerry 提到的那样,TStringList.Sort 使用 AnsiCompareStrAnsiCompareText(我将在几行中解释它是如何做到的).

Like Gerry mentions, TStringList.Sort uses AnsiCompareStr and AnsiCompareText (I'll explain in a few lines how it does that).

但是:TStringList 很灵活,它包含 SortCustomSortCompareStrings,它们都是虚拟的(因此您可以在后代类)
此外,当您调用 CustomSort 时,您可以插入自己的 Compare 功能.

But: TStringList is flexible, it contains Sort, CustomSort and CompareStrings, which all are virtual (so you can override them in a descendant class)
Furthermore, when you call CustomSort, you can plug in your own Compare function.

在这个答案的末尾是一个 Compare 功能,它可以满足您的需求:

At the of this answer is a Compare function that does what you want:

  • 区分大小写
  • 不使用任何语言环境
  • 只比较字符串中字符的序数值

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 的默认 Compare 函数:

By default, the Sort method has a very simple implementation, passing a default Compare function called StringListCompareStrings:

procedure TStringList.Sort;
begin
  CustomSort(StringListCompareStrings);
end;

因此,如果您定义自己的 TStringListSortCompare 兼容 Compare 方法,那么您可以定义自己的排序.
TStringListSortCompare 被定义为一个全局函数,它采用 TStringList 和两个引用您要比较的项目的索引:

So, if you define your own TStringListSortCompare compatible Compare method, then you can define your own sorting.
TStringListSortCompare is defined as a global function taking the TStringList and two indexes referring the items you want to compare:

type
  TStringListSortCompare = function(List: TStringList; Index1, Index2: Integer): Integer;

您可以使用 StringListCompareStrings 作为实现您自己的指南:

You can use the StringListCompareStrings as a guideline for implementing your own:

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:

So, by default TStringList.Sort defers to TList.CompareStrings:

function TStringList.CompareStrings(const S1, S2: string): Integer;
begin
  if CaseSensitive then
    Result := AnsiCompareStr(S1, S2)
  else
    Result := AnsiCompareText(S1, S2);
end;

然后使用底层的 Windows API 函数 CompareString 使用默认用户区域设置 LOCALE_USER_DEFAULT:

Which then use the under lying Windows API function CompareString with the default user locale LOCALE_USER_DEFAULT:

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;

最后是您需要的比较功能.再次限制:

Finally the Compare function you need. Again the limitations:

  • 区分大小写
  • 不使用任何语言环境
  • 只比较字符串中字符的序数值

这是代码:

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 不是封闭的,恰恰相反:它通常是一个非常灵活的架构.
通常只需稍微挖掘一下,看看您可以在何处获得这种灵活性.

Delphi ain't closed, quite the opposite: often it is a really flexible architecture.
It is often just a bit of digging to see where you can hook into the that flexibility.

--jeroen

这篇关于我怎样才能让 TStringList 在 Delphi 中以不同的方式排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆