Einzelnen Beitrag anzeigen

nahpets
(Gast)

n/a Beiträge
 
#1

Sortierung von Stringlisten ab unbestimmter Position

  Alt 10. Okt 2008, 13:07
Hallo,

habe folgendes Problem:

Es sollen Stringlisten sortiert werden, die ähnlich zu CSV-Dateien über ein Trennzeichen getrennte Spalten haben. Die einzelnen Zeilen verfügen nicht über die gleiche Länge, so dass die Trennzeichen an jeder beliebigen Stelle der Zeile vorkommen können. Die Aufgabe ist nun, die Stringliste ab z. B. dem 4. Trennzeichen aufsteigend zu sortieren.
Dies funktioniert mit einem Nachfahren von TStringList und einer eigenen Vergleichsroutine, die über CustomSort aufgerufen wird. Die dort aufzurufende Funktion benötigt als ersten Parameter eine Stringliste, was mit dem Nachfahren problemlos funktioniert. In der eigenen Vergleichsfunktion kann man aber nicht anstelle des ersten Parameter = TStringList die eigene Klasse übergeben, da hier vom Compiler und dem Vorfahren nur TStringList akzeptiert wird. Die Vergleichsfunktion als Funktion der Klasse zu implementieren funktioniert nicht, da CustomSort eine "klassenlose" Funktion erwartet.

Was mich stört: In der Vergleichsfunktion ist ein Typecast auf den Typ des Nachfahren, also auf die eigene Klasse, zu der die Vergleichsfunktion eigentlich gehört (gehören sollte). Ohne den Typecast bekommt jemand, der die Vergleichsfunktion nur mit einer Stringliste aufruft, ein Problem.
Läßt sich der Typecast irgendwie umgehen? Mir sieht das nicht wirklich objektorientiert aus.

Delphi-Quellcode:
.
.
.
interface
.
.
.
type
  tSortStringList = class(TStringList)
  private
    fSortColumn : Integer;
  protected
  public
    procedure Compare;
  published
    property SortColumn : Integer Read FSortColumn Write fSortColumn Default 0;
  end;
.
.
.
implementation
.
.
.
// Stelle im String ermitteln, ab der sortiert werden soll.
Function GetStartPos(s : String; Delimiter : Char; SortColumn : Integer) : Integer;
Var
         iPos : Integer;
         iCount : Integer;
begin
  iPos := 0;
  for iCount := 1 to SortColumn Do iPos := PosEx(Delimiter,s,iPos + 1);
  Inc(iPos);
  Result := iPos;
end;

// Länge des zu sortierenden Strings ermitteln.
Function GetNextPos(s : String; Delimiter : Char; iStartPos : Integer) : Integer;
Var
         iNextPos : Integer;
begin
  iNextPos := PosEx(Delimiter,s,iStartPos);
  case iNextPos of 0 : iNextPos := Length(s); end;
  Result := iNextPos;
end;

function MyCompare(List: TStringList; Index1, Index2: Integer): Integer;
var
         iPos1 : Integer;
         iPos2 : Integer;
         iPosLast1 : Integer;
         iPosLast2 : Integer;
         iColumn : Integer;
begin
  if List is TSortStringList then begin // <-- das stört mich
    iColumn := TSortStringList(List).SortColumn;
  end else begin
    iColumn := 0;
  end;
  // Startposition der Sortierung im ersten String ermitteln.
  iPos1 := GetStartPos(List[Index1],List.Delimiter,iColumn);
  // Startposition der Sortierung im zweiten String ermitteln.
  iPos2 := GetStartPos(List[Index2],List.Delimiter,iColumn);
  // Länge des zu sortierenden (Teil)Strings ermitteln.
  iPosLast1 := GetNextPos(List[Index1],List.Delimiter,iPos1);
  iPosLast2 := GetNextPos(List[Index2],List.Delimiter,iPos2);
  // Groß-/Kleinschreibung beim Vergleich beachten?
  if List.CaseSensitive then begin
    Result := AnsiCompareStr(Copy(List[Index1],
                                   iPos1,
                                   iPosLast1),
                              Copy(List[Index2],
                                   iPos2,
                                   iPosLast2)
                             );
  end else begin
    Result := AnsiCompareText(Copy(List[Index1],
                                   iPos1,
                                   iPosLast1),
                              Copy(List[Index2],
                                   iPos2,
                                   iPosLast2)
                             );
  end;
end;

procedure TSortStringList.Compare;
begin
  Self.CustomSort(MyCompare);
end;
Ein Aufruf könnte so aussehen: (Sortierung ab dem 4. | aufsteigend und Groß-/Kleinschreibung ignorieren)
Delphi-Quellcode:
Stringliste.Delimiter := '|';
Stringliste.SortColumn := 4;
Stringliste.CaseSensitive := false;
Stringliste.Compare;
Wer hat da eine Idee, wie man's besser machen könnte?
  Mit Zitat antworten Zitat