2010-02-01 123 views
13

ich eine einfache TStringList haben. Ich mache einen TStringList.Sort darauf.Wie kann ich TStringList anders zu sortieren in Delphi

Dann merke ich, dass der Unterstrich „_“ Sorten vor dem Großbuchstaben „A“. Dies war im Gegensatz zu einem Paket von Drittanbietern, die den gleichen Text sortierte und _ nach A.

sortiert Nach dem ANSI-Zeichensatz, AZ sind die Zeichen 65 - 90 und _ ist 95. So sieht es aus wie die dritte Partei Paket verwendet diese Reihenfolge und TStringList.Sort ist nicht.

Ich drillte in Muts von TStringList.Sort und es wird mit AnsiCompareStr (Case Sensitive) oder AnsiCompareText (Case Insensitive) sortiert. Ich habe es auf beide Arten versucht, indem ich den CaseSensitive-Wert meiner StringList auf "True" und dann auf "False" gesetzt habe. Aber in beiden Fällen sortiert das "_" zuerst.

Ich kann mich einfach nicht vorstellen, dass dies ein Fehler in TStringList ist. Also muss hier etwas anderes sein, was ich nicht sehe. Was könnte das sein?

Was wirklich wissen müssen, ich ist, wie kann ich meinen TStringList so zu sortieren, zu bekommen, dass sie in der gleichen Reihenfolge wie das andere Paket ist.

Als Referenz Ich bin mit Delphi 2009 und ich bin mit Unicode-Strings in meinem Programm.


So ist die endgültige Antwort ist hier die Ansi vergleicht mit außer Kraft zu setzen, was Sie wollen (zum Beispiel Nicht-ansi vergleicht) wie folgt:

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

Windows-sortiert auch die '_' vor dem' A' so TStringList mindestens consisten mit dem Betriebssystem ist. –

+2

Ergebnisse, die Sie nicht erwarten, bedeutet nicht, dass es ein Fehler ist. Es ist nicht eine Wanze, ist es auf diese Weise des für korrekt den Benutzer (oder OS in Benutzer-Namen) Wahl des Ordnungs- unterstützen. –

+0

Sie schreiben diese Frage mit der Annahme, dass es * ist * eine richtige Art und Weise nicht alphabetische Zeichen zu sortieren. Wo erscheinen Unterstriche in Ihrem Wörterbuch? –

Antwort

35

definieren " korrekt".
i18n Sortierung hängt vollständig von Ihrem Standort ab.
So ganz bin ich mit PA, dass dies kein Fehler ist: Die Standard-Sortieren Verhalten wie entworfen arbeitet i18n zu ermöglichen, richtig zu arbeiten.

Wie Gerry erwähnt, TStringList.Sort verwendet AnsiCompareStr und AnsiCompareText (Ich werde in ein paar Zeilen erklären, wie es das tut).

Aber: TStringList flexibel ist, enthält es Sortieren, CustomSort und CompareStrings, die alle virtuell sind (so können Sie sie in einer abgeleiteten Klasse überschreiben)
Außerdem, wenn Sie CustomSort nennen, Sie können Ihre eigenen verbinden Vergleichen Sie Funktion.

auf die von dieser Antwort ist ein Funktion vergleichen, das tut, was Sie wollen:

  • Case Sensitive
  • Nicht jede locale
  • Man vergleiche nur die Ordnungswert der Zeichen der Strings

CustomSort als diese definiert:

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

standardmäßig die Sortieren Methode hat eine sehr einfache Implementierung, eine Standard vorbei Vergleich Funktion namens StringListCompareStrings:

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

Also, wenn Sie Ihre eigenen TStringListSortCompare definieren kompatibel Vergleichen Sie Methode, dann können Sie Ihre eigene Sortierung definieren.
TStringListSortCompare wird als globale Funktion definiert die TStringList und zwei Indizes nehmen die Elemente beziehen Sie vergleichen wollen:

function StringListCompareStrings(List: TStringList; Index1, Index2: Integer): Integer; 
begin 
    Result := List.CompareStrings(List.FList^[Index1].FString, 
           List.FList^[Index2].FString); 
end; 
:

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

Sie die StringListCompareStrings als Richtlinie Ihre eigenen für die Umsetzung verwenden können

also standardmäßig aufschiebt TStringList.Sort zu TList.CompareStrings:

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

, die dann die unter CompareString mit dem Standard-Benutzergebietsschema LOCALE_USER_DEFAULT liegende Windows-API-Funktion verwenden:

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; 

Schließlich wird die Vergleichen Funktion, die Sie benötigen. Auch hier sind die Grenzen:

  • Case Sensitive
  • Nicht jede locale mit
  • einfach den Ordnungswert der Zeichen der

Strings vergleichen Dies ist der Code:

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 ist nicht geschlossen, ganz im Gegenteil: oft ist es eine wirklich flexible Architektur.
Es ist oft nur ein bisschen zu graben, um zu sehen, wo Sie in diese Flexibilität einhaken können.

--jeroen

+0

Sehr nett! Ich wusste davon, hatte aber noch nicht alles an einem Ort beschrieben. –

+0

Deshalb habe ich es zu einem Community-Wiki gemacht :-) –

5

AnsiCompareStr/AnsiCompareText mehr als Zeichenzahl berücksichtigen. Sie nehmen die Nutzer berücksichtigt locale, so „e“ wird sortieren zusammen mit „é“, „ê“ usw.

, um sie in Ascii Reihenfolge zu machen sortieren, verwenden Sie eine benutzerdefinierte Vergleichsfunktion as described here

0

AnsiCompareStr (CompareString mit LOCALE_USER_DEFAULT) hat Fehler, da es Zeichen mit Punktierung als gleich erhält:

e1 e1 e2 e2

richtige Reihenfolge (zum Beispiel für Tschechisch):

e1 e2 é1 é2

Weiß jemand, wie man diese Fehler bei der Bestellung vermeiden?


11.2.2010: Ich muss mich entschuldigen beschriebenes Verhalten ist vollständig nach linguistischen Regeln. Obwohl ich denke, dass es dumm und "schlecht" ist, ist es kein Fehler in der API-Funktion.

Explorer in Windows XP verwendet so intuitiv filname Bestellung genannt, die bessere Ergebnisse, aber es gibt nicht programmatisch verwendet werden.