Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi TStringList und DelimitedText (https://www.delphipraxis.net/134282-tstringlist-und-delimitedtext.html)

Nersgatt 19. Mai 2009 08:25


TStringList und DelimitedText
 
Hallo,

ich habe ein Problem mit der TStringList und DelimitedText.
Ich bekommen einen Text in Spalten, den ich einlesen muss. Er ist wie folgt aufgebaut:
"Spalte 1"~"Spalte 2"~"Spalte 3"

Dies kann ich mit der TStringList auch wunderbar zerlegen. Aber wenn in einer Spalte ein Text steht, der ein " enthält, kommt die TSTringList ins straucheln und zerlegt die Spalten falsch. Ein Beispiel, um es deutlich zu machen:
Delphi-Quellcode:
var ts : TStringList;
begin

  ts := TStringList.Create;
  try
    ts.Delimiter := '~';
    ts.DelimitedText := '"Spalte 1"~"Spalte 2"~"Spalte 3"';
    showMessage(IntToStr(ts.Count)); {Ergibt 3, wie erwartet}

    ts.DelimitedText := '"Spalte 1"~"Spalte 2"~"Spalte 3"Test""';
    showMessage(IntToStr(ts.Count)); {Ergibt 4, sollte aber 3 ergeben}

  finally
    ts.Free;
  end;

end;
Im zweiten Beispiel sieht man, dass die Spalte zu früh als "fertig" erkannt wurde. In ts.Strings[2] steht dann 'Spalte 3' und in ts.Strings[3] steht 'Test""'. Eigentlich sollte aber in ts.Strings[2] 'Spalte 3"Test"' stehen.
Wie bekomme ich das hin?

Danke!
Jens

Pfoto 19. Mai 2009 08:41

Re: TStringList und DelimitedText
 
Hallo Jens,

hast du schonmal das hier probiert;

Delphi-Quellcode:
 ts.Delimiter:= '~';
  ts.QuoteChar:= '"';
  ts.StrictDelimiter:= true;
Ich meine "StrictDelimiter" könnte da helfen (wenn ich den Hilfe-Text
dazu richtig interpretierte).

Gruß
Jürgen

Nersgatt 19. Mai 2009 08:49

Re: TStringList und DelimitedText
 
Ne, das ändert daran nichts.
Mit strictDelimiter := True verhindert man nur, dass wenn der Delimiter = '~' ist, dass auch z.B. Leerstellen als Delimiter gewertet werden, obwohl ein anderer Delimiter angegeben ist. Das ändert aber nichts an meinem eigentlichen Problem.

Als Hack habe ich jetzt erst mal QuoteChar auf "#" geändert. Dann muss ich die " noch manuell rausnehmen. Das ist aber nur erstmal so, bis ich eine bessere Lösung finde. Zufrieden bin ich damit nicht.

himitsu 19. Mai 2009 09:04

Re: TStringList und DelimitedText
 
Ich vermute mal, daß hier AnsiExtractQuotedStr bei diesem Konstrukt etwas durchdreht,
welches SetDelimitedText intern nutzt ... nachdem dieses mit einem String zurückkehrt, wird das als Ende des des Quoted-Text gewertet und somit ein neuer Eintrag angefangen.

Und AnsiExtractQuotedStr gibt ja nur den String bis zum nächsten Quote-Char zurück.

TStrings.GetDelimitedText und SysUtils.AnsiExtractQuotedStr kann man nicht überschreiben, also bliebe dir dann nur noch übrig dir eine eigene GetDelimitedText zu schreiben.

Satty67 19. Mai 2009 09:10

Re: TStringList und DelimitedText
 
Wenn es keine StringListe sein muss, sondern auch ein Array Of String sein darf:

wie geht Explode damit um?
(kann es mit D5 nicht testen)

himitsu 19. Mai 2009 09:35

Re: TStringList und DelimitedText
 
Da ExplodeExplode keinen Quote kennt, teilt es an jedem Delimiter,
selbst wenn der in einem "Qoute" (was es ja nicht beachtet) drin wäre.

Also die beiden obrigen Beispieltext würden wie gewünscht geteilt (allerdings die QuoteChars noch enthalten), aber
Delphi-Quellcode:
ts.DelimitedText := '"Spalte 1"~"Spalte~2"~"Spalte 3"';
showMessage(IntToStr(ts.Count)); {Ergibt 4, statt 3}

Klaus01 19. Mai 2009 09:37

Re: TStringList und DelimitedText
 
Guten Morgen,

ich habe das explode mal etwas umgebaut so
das jetzt eine StringList zurückgegeben wird.

Delphi-Quellcode:
// Explode trennt S in die durch Separator getrennten Elemente auf. Wenn Limit
// > 0 ist, so werden max. Limit Elemente getrennt, wobei im letzen Element
// die Restzeichenkette steht.

function Explode(const Separator, S: string; Limit: Integer = 0): TStringList;
var
  SepLen: Integer;
  F, P: PChar;
  Index: Integer;
begin
  result := TStringList.Create;
  if (S = '') or (Limit < 0) then Exit;
  if Separator = '' then
  begin
    Result.add(S);
    Exit;
  end;
  SepLen := Length(Separator);

  Index := 0;
  P := PChar(S);
  while P^ <> #0 do
  begin
    F := P;
    P := AnsiStrPos(P, PChar(Separator));
    if (P = nil) or ((Limit > 0) and (Index = Limit - 1)) then
      P := StrEnd(F);
    result.Add(copy(AnsiString(F),0,P-F));
    inc(index,1);
    if P^ <> #0 then Inc(P, SepLen);
  end;

end;

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  ts : TStringList;
  ts2: TStringList;
  s:String;
begin

  ts := TStringList.Create;
  s:='"Spalte 1"~"Spalte 2"~"Spalte 3"Test""';
  try
    ts.Delimiter := '~';
    ts.DelimitedText := '"Spalte 1"~"Spalte 2"~"Spalte 3"';
    showMessage(IntToStr(ts.Count)); {Ergibt 3, wie erwartet}

    ts.DelimitedText := s;
    showMessage(IntToStr(ts.Count)); {Ergibt 4, sollte aber 3 ergeben}

    ts2:=explode('~',s));
    showMessage(IntToStr(ts2.Count)); // Ergibt 3, SubStrings sind aber noch in "" eingefasst
    ts2.free;
  finally
    ts.Free;
  end;

end;
Grüße
Klaus

[Korrektur vorgenommen]


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:39 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz