Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   CSV-Datei mit /sb (https://www.delphipraxis.net/198000-csv-datei-mit-sb.html)

Harry Stahl 25. Sep 2018 18:18

CSV-Datei mit /sb
 
Habe eine csv-Datei von einem Kunden erhalten, wo ein hin und wieder vorkommendes "/sb" im Text (in dem freien Info-Feld) dazu führt, dass -per Stringlist.loadfromfile - an dieser Stelle ein Zeilenumbruch stattfindet.

Wenn ich die Datei in Notepad.exe öffne, findet der Umbruch nicht statt, die Datei hat 21609 Datensätze, mit Delphi Stringlist geöffnet sind es aber 27704 Datensätze.

Hat jemand eine Ahnung, warum das so ist und wie man es hinbekommt, dass auch die Stringlist nur 21609 Zeilen generiert?

Uwe Raabe 25. Sep 2018 18:36

AW: CSV-Datei mit /sb
 
Kannst du mal eine Beispieldatei und etwas Code zeigen, mit dem man das nachstellen kann?

Delphi.Narium 25. Sep 2018 18:40

AW: CSV-Datei mit /sb
 
Hilft das eventuell? : http://docwiki.embarcadero.com/Libra...trictDelimiter

Drecktrah 25. Sep 2018 19:00

AW: CSV-Datei mit /sb
 
"/sb" kommt vermutlich 27704 - 21609 = 6095 mal im Text vor?

Harry Stahl 25. Sep 2018 19:26

AW: CSV-Datei mit /sb
 
OK, habe da mal genauer mit einem Hex-Editor reingesehen. Nach /sb folgt "0A" (oder asci #10), was ja einen zeilenvorschub repräsentiert.

Die Stringlist macht nach dem einlesen (Stringlist.loadfromfile) aber da ein #13#10 draus.

/sb könnte ja für "soft break" stehen oder so.

Ist mir jedenfalls noch nicht untergekommen.

Mein Problem kann ich erst mal lösen, indem ich nach dem Einlesen der Datei z.B.

Delphi-Quellcode:
stringlist.text := ReplaceStr (stringlist.text, '/sb' + #13#10, ' ');


aufrufe, um die richtige Zeilenzahl zu bekommen.

(tatsächlich werde ich es nicht durch ein Leerzeichen ersetzen, sondern durch ein anderes Sonderzeichen, dass in meinen mehrzeiligen Feldern (Memo) den Zeilenumbruch repräsentiert).

Interessant finde ich aber, dass Windows Notepad so eine Zeile als eine Zeile einliest...

Nachtrag: Windows-Notepad ignoriert einfach #10 Zeichen und macht keinen neue Zeile auf, auch ohne /sb

Soweit ich das jetzt raus gefunden habe, wird in diesem Feld, das mehrzeiligen Text repräsentiert, das erste #10-Zeichen mit /sb eingeleitet, es können aber noch weitere #10 Zeichen (ohne /sb Einleitung) innerhalb des Textes für dieses Feld vorkommen.

Kann das irgendein Standard sein? Sehe ich jedenfalls zum ersten mal.

Suchen und ersetzen reicht da nicht, da muss ich das wohl als Memorystream einlesen und jedes einzelne #10 Zeichen, das nicht im Verbund mit #13#10 steht, eliminieren (bzw. durch mein eigenes Kennzeichen ersetzen)....

himitsu 25. Sep 2018 20:11

AW: CSV-Datei mit /sb
 
Zitat:

Zitat von Harry Stahl (Beitrag 1414161)
OK, habe da mal genauer mit einem Hex-Editor reingesehen. Nach /sb folgt "0A" (oder asci #10), was ja einen zeilenvorschub repräsentiert.

Gerade Notepad hat das Problem, dass es #10 nicht als Zeilenumbruch, sondern als Zeichen interpretiert.
Und da für #10 im Font nichts hinterlegt ist, hat das in der Anzeige eine Breite von 0, was du nur bemerkst, wenn du mit den Cursortasten zeichenweise durch den Text gehst.

p80286 26. Sep 2018 08:50

AW: CSV-Datei mit /sb
 
Wenn man mit csv-Dateien hantiert, ist "Zeile" ein untauglicher Begriff. en Datensatz wird durch x0D0A (#13#10) begrenzt, es sei denn diese Zeichenkombination befindet sich zwischen zwei " dann handelt es sich um ein (text)Feld das einen mehrzeiligen Text enthält.

Eine csv-Datei mit dem Notepad zu öffnen oder sie in eine Stringliste einzulesen, ist nicht in jedem fall zuverlässig und eignet sich allenfalls, um einen Überblick zu erhalten.

Gruß
K-H

U.U. kann man auch andere Vereinbarungen bezgl. der Feld und Satz-seperatoren treffen, aber das ist Vereinbarungssache.

Sherlock 26. Sep 2018 09:22

AW: CSV-Datei mit /sb
 
NotePad++ ist die bessere Lösung zur Fehlersuche in solchen Dateien. Da kann man sich die "Steuerzeichen" anzeigen lassen und sieht eigentlich sehr schnell was los ist.

Sherlock

jobo 26. Sep 2018 13:07

AW: CSV-Datei mit /sb
 
Was alles unter ".csv" so kursiert ist zwar nicht ganz zufällig, aber oft ist es nicht mal das Comma, aus Comma-Separated-Values, was man als Trenner findet.
[quote]..
As indicated by carriage return or linefeed characters, each line in the file is then appended in the list as a string.
..[quote]
http://docs.embarcadero.com/products...le@string.html

Auch da kann man sich über die Formulierung streiten, aber es wird jedenfalls beschrieben, das 2 verschiedene Zeichen als Delimiter des Zeilenendes akzeptiert werden.

Die Funktion tut also erstmal, was sie soll, oder?

Uwe Raabe 26. Sep 2018 13:39

AW: CSV-Datei mit /sb
 
Das ist hardcoded in
Delphi-Quellcode:
TStrings.SetTextStr
.

Delphi-Quellcode:
          while not (P^ in [#0, #10, #13]) do Inc(P);


Da die Methode aber virtuell ist, könntest du die überschreiben und durch einen für diesen Fall passenden Code ersetzen.

ergeka 26. Sep 2018 15:15

AW: CSV-Datei mit /sb
 
Bei einem ähnlichem Fall lese ich die Fremddatei zuerst mit einem StringStream ein.
Der 'Roh-String' wird bearbeitet und kann dann der StringList übergeben werden.

Delphi-Quellcode:
  ASL := TStringList.Create;
  try
    StrStream := TStringStream.Create;
    try
      {.. hier reparieren wir die CRCRLF Orgie aus dem Textfile ..}
      StrStream.LoadFromFile(AFileName);
      RawSWData := StrStream.DataString;
      RawSWData := StringReplace(RawSWData,#13#13#10,'',[rfReplaceAll]);
      ASL.Text := RawSWData;
      //mit ASL arbeiten
    finally
      StrStream.Free;
    end;
  finally
    ASL.Free;
  end;
Gruß

Ralf

juergen 26. Sep 2018 21:09

AW: CSV-Datei mit /sb
 
Hallo zusammen,

bis jetzt hatte ich das auch immer so gemacht wie Uwe es gezeigt hat. Dafür habe ich mir die original System.Classes.pas in den entsprechenden Projektordner kopiert und diese Unit dann angepasst.
Nachteil: Wenn ich mal eine neuere Delphiversionen einsetzen sollte, muss ich ggf. die System.Classes neu kopieren und bearbeiten.

Von daher gefällt mir der Ansatz von Ralf ganz gut.
Vorsichtshalber möchte ich nachfragen ob meine Deklaration von RawSWData so richtig ist (als string)?

Delphi-Quellcode:
RawSWData: string;

Vielen Dank!

Uwe Raabe 26. Sep 2018 21:19

AW: CSV-Datei mit /sb
 
Zitat:

Zitat von juergen (Beitrag 1414285)
bis jetzt hatte ich das auch immer so gemacht wie Uwe es gezeigt hat. Dafür habe ich mir die original System.Classes.pas in den entsprechenden Projektordner kopiert und diese Unit dann angepasst.

Das habe ich aber nicht so gemeint! Das würde ja bedeuten, daß sich dann alle
Delphi-Quellcode:
TStringList
im Projekt so verhalten. Eventuell muss man ja auch unterschiedliche CSV-Dateien mit anderen abstrusen Konventionen einlesen können. Für den konkreten Anwendungsfall hatte ich mir eher etwas wie dieses vorgestellt:
Delphi-Quellcode:
type
  TSoftBreakStringList = class(TStringList)
  protected
    procedure SetTextStr(const Value: string); override;
  end;

procedure TSoftBreakStringList.SetTextStr(const Value: string);
var
  P, Start: PChar;
  S: string;
begin
  if CompareStr(LineBreak, sLineBreak) <> 0 then begin
    inherited;
    Exit;
  end;

  BeginUpdate;
  try
    Clear;
    P := Pointer(Value);
    if P <> nil then begin
      while P^ <> #0 do begin
        Start := P;
        while not (P^ in [#0, #13]) do Inc(P);
        SetString(S, Start, P - Start);
        Add(S);
        if P^ = #13 then Inc(P);
        if P^ = #10 then Inc(P);
      end;
    end;
  finally
    EndUpdate;
  end;
end;

juergen 26. Sep 2018 21:28

AW: CSV-Datei mit /sb
 
@Uwe,

das hatte ich mir schon gedacht dass du das nicht so machst wie ich. Ich wusste es halt nicht besser.
Danke für dein Beispiel, somit habe ich wieder was gelernt! :dp:

Gute N8!

ergeka 26. Sep 2018 21:37

AW: CSV-Datei mit /sb
 
Zitat:

Zitat von juergen (Beitrag 1414285)
Von daher gefällt mir der Ansatz von Ralf ganz gut.
Vorsichtshalber möchte ich nachfragen ob meine Deklaration von RawSWData so richtig ist (als string)?

Delphi-Quellcode:
RawSWData: string;

Vielen Dank!

Hallo Jürgen,

ja, das ist bei mir als String deklariert.

Gruß

Ralf

juergen 26. Sep 2018 21:48

AW: CSV-Datei mit /sb
 
@Ralf,

danke für deine Antwort! :thumb:

Gruß
Jürgen

Harry Stahl 26. Sep 2018 22:12

AW: CSV-Datei mit /sb
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1414286)
Zitat:

Zitat von juergen (Beitrag 1414285)
bis jetzt hatte ich das auch immer so gemacht wie Uwe es gezeigt hat. Dafür habe ich mir die original System.Classes.pas in den entsprechenden Projektordner kopiert und diese Unit dann angepasst.

Das habe ich aber nicht so gemeint! Das würde ja bedeuten, daß sich dann alle
Delphi-Quellcode:
TStringList
im Projekt so verhalten. Eventuell muss man ja auch unterschiedliche CSV-Dateien mit anderen abstrusen Konventionen einlesen können. Für den konkreten Anwendungsfall hatte ich mir eher etwas wie dieses vorgestellt:
Delphi-Quellcode:
type
  TSoftBreakStringList = class(TStringList)
  protected
    procedure SetTextStr(const Value: string); override;
  end;

procedure TSoftBreakStringList.SetTextStr(const Value: string);
var
  P, Start: PChar;
  S: string;
begin
  if CompareStr(LineBreak, sLineBreak) <> 0 then begin
    inherited;
    Exit;
  end;

  BeginUpdate;
  try
    Clear;
    P := Pointer(Value);
    if P <> nil then begin
      while P^ <> #0 do begin
        Start := P;
        while not (P^ in [#0, #13]) do Inc(P);
        SetString(S, Start, P - Start);
        Add(S);
        if P^ = #13 then Inc(P);
        if P^ = #10 then Inc(P);
      end;
    end;
  finally
    EndUpdate;
  end;
end;

Zur Info: Das Einlesen der Datei funktioniert auch mit dieser Variante, nur hat man danach natürlich keine Möglichkeit mehr, die Softbreaks, z.B. bei einem importierten Text für ein mehrzeiliges Memofeld zu setzen (da ja alle #10 beim Einlesen übergangen werden).

Uwe Raabe 26. Sep 2018 23:08

AW: CSV-Datei mit /sb
 
Zitat:

Zitat von Harry Stahl (Beitrag 1414291)
(da ja alle #10 beim Einlesen übergangen werden).

Hast du das probiert oder vermutest du das nur?
Wenn ich mich nicht täusche, werden nur die #10 übergangen, die nach einem #13 kommen. Alle anderen werden mit SetString in S übertragen.

Harry Stahl 27. Sep 2018 20:40

AW: CSV-Datei mit /sb
 
Ich hatte den Code wohl an einer Stelle falsch verstanden und hatte es aber auch zusätzlich probiert.

Zum Test hatte ich dann

memo1.lines.text = stringlist.text

probiert und gesehen, dass kein Zeilenumbruch im TMemo stattfand, daher ging ich davon aus, dass die #10 Zeichen entfallen wären.

Aber jetzt den Code noch mal genauer angesehen und nein, die #10 werden nicht überlesen.

Das TMemo verhält sich interessanterweise genau so wie Notepad, wenn man den Text so zuweist, wie oben von mir dargestellt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:56 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