Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Neuen Beitrag zur Code-Library hinzufügen (https://www.delphipraxis.net/33-neuen-beitrag-zur-code-library-hinzufuegen/)
-   -   Delphi Nur eine Spalte aus CSV-Datei auslesen und verarbeiten (https://www.delphipraxis.net/206128-nur-eine-spalte-aus-csv-datei-auslesen-und-verarbeiten.html)

AlHuNcEaR 20. Nov 2020 23:30

Nur eine Spalte aus CSV-Datei auslesen und verarbeiten
 
Guten Tag,
in meinem Programm, möchte ich aus einer CSV-Datei (mit 2 Spalten) nur die Werte aus der 2.Spalte speichern und verarbeiten.
Beispiel wäre aus allen Zahlen der 2.Spalte die höchste zu bestimmen.
Hat jemand dafür einen Ansatz bzw. Lösung?
Vielen Dank!!!

hoika 21. Nov 2020 07:51

AW: Nur eine Spalte aus CSV-Datei auslesen und verarbeiten
 
Hallo,
du musst die Datei komplett lesen und die Spalte extrahieren.
Ich nehme dafür immer 2 TStringList, eine für die Datei und eine zum Trennen der jeweiligen Zeile (Delimimter, DelimtedText)

juergen 21. Nov 2020 11:33

AW: Nur eine Spalte aus CSV-Datei auslesen und verarbeiten
 
Hallo,

eine weitere Möglichkeit wäre ein ClientDataSet. Damit kannst über CDS.Fields[x].AsString(?) direkt die "Spalte" ansprechen.
Ein ClientDataSet bietet auch die Möglichkeit eine csv-Datei direkt zu laden (LoadFromFile()).
Allerdings weiß ich grad nicht ob das Delphi-eigene ClientDataSet sowas auch bietet, da ich nur mit dem DevExpress-MemDataSet arbeite. Ich vermute aber schon.
Die Einarbeitung in ein ClientDataSet ist ein wenig höher, bietet aber auf Sicht IMHO besseres Handling/ Programmierbarkeit.

himitsu 21. Nov 2020 12:18

AW: Nur eine Spalte aus CSV-Datei auslesen und verarbeiten
 
Am "Einfachsten" wäre es, eine fertige Lösung für CSV zu verwenden ... alles einzulesen zu lassen und dann nur die zweite Spalte zu nehmen stellt ja kein Problem dar. (außer vielleicht die Datei ist viel zu groß für den Arbeitsspeicher)
Dazu würde z.B. das ClientDataSet zählen oder irgendeine CSV-Komponente.

Ja, zwei TStringList für Zeilen und Spalten sind eine gängige einfache Lösung für Sowas (die SuFu hilft),
oder ganz modern TFile.ReadAllLines und String.Split mit einer For-In-Schleife, für alle die neuere Klassen/Funktionen verwenden und etwas über Enumeratoren und RecordHelper lernen wollen. :stupid:

Zitat:

Delimimter, DelimtedText
Und StrictDelimiter nicht vergessen, nicht dass man sich dann etwas wundert.

AlHuNcEaR 22. Nov 2020 13:29

AW: Nur eine Spalte aus CSV-Datei auslesen und verarbeiten
 
Danke an alle für die Antworten!

Benmik 23. Nov 2020 17:40

AW: Nur eine Spalte aus CSV-Datei auslesen und verarbeiten
 
Wäre es bei einer so einfachen Ausgangssituation nicht am einfachsten und schnellsten, die Datei einzulesen, #9 anzuspringen, Wert auslesen, #13#10 anzuspringen und so weiter?

himitsu 23. Nov 2020 17:44

AW: Nur eine Spalte aus CSV-Datei auslesen und verarbeiten
 
Am Schnellsten vielleicht. (wobei #9 natürlich auch , oder ; oder sonstwas sein kann .. drum nennen es Manche auch DSV statt CSV oder sagen einfach "character" statt "comma")
Mit "am Einfachstes" endet es schon, wenn die Zeilen nicht mit #13#10 enden, sondern eventuell auch mit #10 oder #13.

Benmik 23. Nov 2020 18:40

AW: Nur eine Spalte aus CSV-Datei auslesen und verarbeiten
 
Ich wusste, sowas würde kommen...:thumb:

Ich gehe einfach mal davon aus, dass a) die Dateien vielleicht sogar von ihm selbst stammen b) CSV-Dateien praktisch immer #9 und #13#10 haben und c) er notfalls nachschaut.

himitsu 23. Nov 2020 19:40

AW: Nur eine Spalte aus CSV-Datei auslesen und verarbeiten
 
Drum auch TStringList ... die macht das Trennen der Zeilen (#10, #13 oder #13#10), aber es geht auch ReadLn oder eben z.B. ein PosEx(#13#10).
Und dann nochmal eine weitere TStringList.DelimitedText für das Trennen am "Komma", wofür man auch jede beliebige andere SplitString-Funktion nehmen kann,
So man muß sich um fast nichts kümmern und ist alles schon von Haus aus im Delphi vorhanden. :zwinker:

ReadAllLines erzeugt ein TArray<string> mit allen Zeilen (wie die erste StringList)
Bei diesem Code muß man aber aufpassen, den wenn in irgendeiner Zeile nicht 2 Spalten, also mindestens 1 Delimiter vorkommt, dann knallt es, wenn man so ungeprüft auf das Array zugreift. :oops:
Delphi-Quellcode:
for var Values in TFile.ReadAllLines('C:\irgendwo\file.csv') do
  MacheWasMitDerZweitenSpalte(Values.Split([#9])[1]);
Man könnte das ganze Problem sogar mit einem RegEx lösen, also irgendwie so
Delphi-Quellcode:
for var Match in TRegEx.Matches(TFile.ReadAllText('C:\file.csv'), '^[^\t]*\t([^\t]*)', [roMultiLine]) do
  DoWithSecondValue(Match.Groups[1]); // Match.Value

Fuchtel 23. Nov 2020 19:48

AW: Nur eine Spalte aus CSV-Datei auslesen und verarbeiten
 
Meine Lösung:

Eine von TStringList abgeleitete Komponente (z,B,.: TStringList_Ex);

Uberschreibe
Code:
function Add(const S: string): Integer;
var
  sp: Szring;
begin
  Result := GetCount;
  sp := Part(S, <cSep>, 2);
  Insert(Result, sp);
end;
Wobei cSep dein Separator (hier #09 ist)


Code:
function Part(const sVar: String; const cSep: Char; UV: Integer): String;
var
  P, S : PChar;
  i, j : Integer;
begin
  P := Pointer(sVar);
  S := P;
  i := 1;
  j := UV; Inc(j);
  If P <> nil then
    begin
      While (P^ <> #0) do
        begin
          If P^ = cSep then
            begin
              INC(i);
              If i = UV then S := P;
              If i = j then break;
            end;
          P := NextChar(P);
        end;
    If UV > 1 then INC(s);
    If (i >= UV) and (UV > 0) then
        System.SetString(Result, S, P - S)
      else
        Result := '';
  end;
end;
Falls NextChar fehlt:

Code:
function NextChar(P: PChar): PChar;
begin
  Result := P;
  if (Result <> nil) and (Result^ <> #0) then
  begin
    Inc(Result);
    {$IFDEF UNICODE}
    if Result^.IsLowSurrogate then
      Inc(Result);
    while Result^.GetUnicodeCategory = TUnicodeCategory.ucNonSpacingMark do
      Inc(Result);
    {$ENDIF}
  end;
end;
Wobei, wenn Du nur den größten Wert ermitteln willst, nimm nur daraus die Proceduren:

Code:
procedure TStrings.LoadFromFile(const FileName: string);
Code:
procedure TStrings.LoadFromStream(Stream: TStream; Encoding: TEncoding);
und fuer Add

Code:
function Add(const S: string): Integer;
var
  sp: String;
  i: Integer
begin
  sp := Part(S, <cSep>, 2);
  FMax := Max(FMax, StrToIntDef(sP, - MaxInt));
end;


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