15

私は単純な TStringList を持っています。私はそれに TStringList.Sort を実行します。

次に、アンダースコア「_」が大文字の「A」の前にソートされることに気付きました。これは、同じテキストをソートし、A の後に _ をソートするサード パーティのパッケージとは対照的でした。

ANSI 文字セットによると、AZ は文字 65 ~ 90 で、_ は 95 です。したがって、サードパーティ パッケージはその順序を使用しているように見えますが、TStringList.Sort は使用していません。

TStringList.Sort の中身を掘り下げたところ、AnsiCompareStr (大文字と小文字を区別) または AnsiCompareText (大文字と小文字を区別しない) を使用して並べ替えています。StringList の CaseSensitive 値を true に設定してから false に設定して、両方の方法で試しました。ただし、どちらの場合も、「_」が最初にソートされます。

これが TStringList のバグだとは思えません。ですから、私が見ていない何かがここにあるに違いありません。それは何でしょうか?

本当に知っておく必要があるのは、TStringList を他のパッケージと同じ順序になるように並べ替えるにはどうすればよいかということです。

参考までに、私は Delphi 2009 を使用しており、プログラムで 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;
4

3 に答える 3

37

「正しく」を定義します。
i18nの並べ替えは、ロケールに完全に依存します。したがって、これはバグではないというPA
の 見解に完全に同意します。デフォルトのソート動作は、i18n が適切に機能するように設計されたとおりに機能します。

Gerryが述べているように、TStringList.SortAnsiCompareStrAnsiCompareTextを使用します (それがどのように行われるかを数行で説明します)。

しかし: TStringList は柔軟性があり、SortCustomSortCompareStringsを含み、これらはすべて仮想です (したがって、子孫クラスでそれらをオーバーライドできます)
。 さらに、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というデフォルトのCompare関数を渡します。

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

そのため、独自のTStringListSortCompare互換のCompareメソッドを定義すると、独自の並べ替えを定義できます。
TStringListSortCompare は、TStringList と、比較する項目を参照する 2 つのインデックスを受け取るグローバル関数として定義されます。

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 関数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;

最後に、必要なCompare関数です。再び制限:

  • 大文字と小文字を区別
  • ロケールを使用していない
  • 文字列の文字の序数値を比較するだけです

これはコードです:

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 は非常に柔軟なアーキテクチャです。
多くの場合、その柔軟性をどこに接続できるかを確認するのは、ほんの少しの調査です。

--jeroen

于 2010-02-01T10:24:27.187 に答える
5

AnsiCompareStr / AnsiCompareText は文字数以上を考慮します。ユーザーのロケールが考慮されるため、「e」は「é」、「ê」などと一緒にソートされます。

アスキー順に並べ替えるには、ここで説明されているようにカスタム比較関数を使用します

于 2010-02-01T07:18:36.140 に答える
0

AnsiCompareStr(LocalE_USER_DEFAULTを使用したCompareString)には、句読点が等しい文字を取得するため、障害があります。

e1é1e2é2

正しい順序は次のとおりです(たとえばチェコ語の場合):

e1e2é1é2

注文時にこのエラーを回避する方法を知っている人はいますか?


11.2.2010:説明されている動作が完全に言語規則に従っていることをお詫びする必要があります。ばかげて「悪い」と思いますが、API関数のエラーではありません。

Windows XPのExplorerは、より良い結果をもたらす、いわゆる直感的なfilname順序を使用しますが、プログラムで使用することはできません。

于 2010-02-10T14:28:21.470 に答える