Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何让TStringList在Delphi中进行不同的排序_Delphi_Sorting_Ansi_Tstringlist - Fatal编程技术网

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

如何让TStringList在Delphi中进行不同的排序,delphi,sorting,ansi,tstringlist,Delphi,Sorting,Ansi,Tstringlist,我有一句简单的英语。我做了一个TStringList排序 然后我注意到下划线“u”排序在大写字母“A”之前。这与第三方软件包不同,第三方软件包对同一文本进行排序,并在a之后进行排序 根据ANSI字符集,A-Z是字符65-90,u是95。所以看起来第三方软件包使用了这个顺序,而TStringList.Sort没有 我深入研究了TStringList.Sort的内部,它是使用AnsiCompareStr(区分大小写)或AnsiCompareText(不区分大小写)进行排序的。我尝试了两种方法,将St

我有一句简单的英语。我做了一个TStringList排序

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

根据ANSI字符集,A-Z是字符65-90,u是95。所以看起来第三方软件包使用了这个顺序,而TStringList.Sort没有

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

我无法想象这是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;

AnsiCompareStr/AnsiCompareText考虑的字符数不止一个。它们考虑了用户的语言环境,因此“e”将与“é”、“ê”等一起排序

要使其按Ascii顺序排序,请使用自定义比较函数定义“正确”。
排序完全取决于您的区域设置。
因此,我完全同意这不是一个bug:默认的排序行为可以让i18n正常工作

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

但是:TStringList是灵活的,它包含排序自定义排序比较,这些都是虚拟的(因此您可以在子类中重写它们)
此外,当您调用CustomSort时,您可以插入自己的比较功能

在这个答案的末尾是一个比较函数,它可以满足您的需要:

  • 区分大小写
  • 不使用任何区域设置
  • 只需比较字符串字符的序数值
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函数:

procedure TStringList.Sort;
begin
  CustomSort(StringListCompareStrings);
end;
因此,如果您定义自己的TStringListSortComparecompatibleCompare方法,那么您可以定义自己的排序。
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;
然后将Windows API函数与默认用户区域设置一起使用:

最后是所需的比较功能。再次强调限制:

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

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并不是封闭的,恰恰相反:它通常是一个非常灵活的体系结构。
这通常只是一个挖掘,看看你可以钩到哪里的灵活性

--jeroen

AnsiCompareStr(与区域设置_USER_DEFAULT进行比较)有错误,因为它获取的点状字符相等:

e1 é1 e2 é2

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

e1 e2 é1 é2

有人知道如何避免订购时出现这种错误吗


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


Windows XP中的资源管理器使用了所谓的直观的filname排序,它提供了更好的结果,但不能以编程方式使用。

Windows还将
\uUcode>排序在
A
之前,因此TStringlist至少与操作系统一致。获得您意想不到的结果并不意味着它是一个bug。这不是一个bug,它的设计目的是为了正确支持用户(或代表用户的操作系统)选择排序顺序。你写这个问题的前提是有一种对非字母字符进行排序的正确方法。在你的字典里下划线单词出现在哪里?@Rob:我不需要正确的方式。我真的只需要一个一致的方式,这样我的程序就可以对TStringList和我的第三方软件包使用相同的顺序。您在问题的几个地方提到,您需要正确或适当的排序顺序。我会修改你的问题来改变它,因为它不是你真正需要的。非常好!我知道这一点,但以前没有在一个地方看到所有这些描述。TStringList排序是完全错误的,因为它不符合内置运算符所诱导的顺序('灵活的升序或降序:函数CompareSalary3(List:TStringList;Index1,Index2:Integer):整数;开始//升序:结果:=CompareString(list[index1],list[index2]);//降序只是否定结果结果:=-CompareString(list[index1],list[index2]);结束;
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;