代码之家  ›  专栏  ›  技术社区  ›  lkessler

在Delphi中如何让tstringlist进行不同的排序

  •  13
  • lkessler  · 技术社区  · 15 年前

    我有一个简单的电话簿。我做一个电话单。整理一下。

    然后我注意到下划线“u”排在大写字母“a”之前。这与第三方软件包不同,第三方软件包对同一文本进行排序,并在a之后进行排序。

    根据ANSI字符集,a-z是字符65-90,u是95。所以看起来第三方软件包使用的是order和tstringlist。

    我深入到tstringlist.sort的内部,它使用ansicompartrest(区分大小写)或ansicompartext(不区分大小写)进行排序。我尝试了两种方法,将StringList的区分大小写值设置为true,然后设置为false。但在这两种情况下,“_uu”都是第一类。

    我只是无法想象这是一个tstringlist中的bug。所以这里肯定还有我看不到的东西。那可能是什么?

    我真正需要知道的是,如何让我的tstringlist排序,使它与另一个包的顺序相同。

    作为参考,我使用的是Delphi2009,在我的程序中使用的是Unicode字符串。


    因此,这里的最后一个答案是重写与所需内容(如非ANSI比较)的ANSI比较,如下所示:

    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;
    
    3 回复  |  直到 15 年前
        1
  •  35
  •   Dane    8 年前

    定义“正确”。
    i18n 排序完全取决于您所在的地区。
    所以我完全同意 PA 这不是错误:默认 排序 行为的设计允许I18N正常工作。

    喜欢 Gerry 提到, tstringlist.sort排序 使用 安西姆帕雷斯特 异步文本 (我将用几行文字解释它是如何做到的)。

    但是:tstringlist是灵活的,它包含 排序 , 定制排序 并列 ,它们都是虚拟的(因此您可以在子类中重写它们)
    此外,当你打电话时 自定义排序 ,您可以插入自己的 比较 功能。

    答案是 比较 执行所需操作的函数:

    • 区分大小写
    • 不使用任何区域设置
    • 只需比较字符串字符的序数值

    定制排序 定义如下:

    procedure TStringList.CustomSort(Compare: TStringListSortCompare);
    begin
      if not Sorted and (FCount > 1) then
      begin
        Changing;
        QuickSort(0, FCount - 1, Compare);
        Changed;
      end;
    end;
    

    默认情况下, 排序 方法的实现非常简单,传递默认值 比较 函数称为 字符串列表比较字符串 以下内容:

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

    所以,如果你定义了你自己的 t列表排序比较 兼容的 比较 方法,然后您可以定义自己的排序。
    tstringlistsortcompare定义为一个全局函数,使用tstringlist和两个引用要比较的项的索引:

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

    你可以使用 字符串列表比较字符串 作为实施自己的准则:

    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;
    

    然后使用隐藏的Windows API函数 CompareString 使用默认用户区域设置 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;
    

    最后 比较 你需要的功能。同样的限制:

    • 区分大小写
    • 不使用任何区域设置
    • 只需比较字符串字符的序数值

    这是代码:

    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不是封闭的,恰恰相反:它通常是一个非常灵活的体系结构。
    通常只需要一点点的挖掘,看看你能从哪里获得这种灵活性。

    ——杰罗恩

        2
  •  5
  •   Gerry Coll    15 年前

    ansicompartrest/ansicompartext考虑的字符数多于。他们考虑到用户的区域设置,因此“e”将与“_”、“_”等进行排序。

    要使其按ASCII顺序排序,请使用自定义比较函数 as described here

        3
  •  0
  •   Roman Stedronsky    15 年前

    ansicompartrest(与locale_user_default比较)有错误,因为它获取的字符的punctation等于:

    E1 γ1 E2 γ2

    正确的顺序是(例如捷克语):

    E1 E2 γ1 γ2

    有人知道如何在订购时避免这个错误吗?


    11.2.2010:我必须道歉,所描述的行为完全符合语言规则。虽然我认为这是愚蠢和“坏”的,但它不是API函数中的错误。

    windows xp中的explorer使用了所谓的直观的filname排序,它提供了更好的结果,但不能用于编程。

    推荐文章