Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - CSV-Datei lesen
GuaAck - Di 23.07.13 22:52
Titel: CSV-Datei lesen
Hallo,
ich möchte eine CSV-Datei auswerten, also eine Textdatei mit Zeilen der Art:
Wert1;Wert2;Wert3;
Ich kenne den Typ von Wert1, Wert2 und Wert 3.
Ich habe mal eine sehr schöne Funktion in Delphi dafür genutzt, leider habe ich die aber in der Hilfe und meinen Projekten nicht mehr finden können. Es ging im Prinzip so:
Trennzeichen_festlegen (';');
Lese(Wert1); {Liest bis ';' und setzt dann den Lesezeiger auf die Position nach dem nächsten ';'}
Lese(Wert2);
Lese(Wert3);
Vielleicht war es eine Funktion in der Stringverarbeitung, vielleicht auch im Bereich TStream, da habe ich aber nichts finden können.
Kennt jemand so eine Funktion?
(Klar, als Notlösung scanne ich den String einer Zeile selbst, zerlege ihn in seine Einzelteile und wandele z. B. mit strtoint, strtofloat usw. um. Ist aber umständlicher.)
Gruß GuaAck
OldGrumpy - Mi 24.07.13 00:14
Wenn es nicht allzu viele Daten sind und die Geschwindigkeit nicht zu kritisch ist, kann man TStringList dafür missbrauchen, zum Beispiel so:
- Zwei TStringList instantiieren.
- Ab (IIRC) D2005 unbedingt StrictDelimiter:=True setzen (war früher Default, ab der Version ist es umgekehrt), Delimiter auf Semikolon setzen.
- In die erste die CSV-Datei laden (LoadFromFile)
- In einer Schleife jeweils eines der Items der ersten TStringList als DelimitedText der zweiten StringList setzen. Und schon ist die CSV-Zeile getrennt.
Stößt allerdings an seine Grenzen, wenn das Trennzeichen auch innerhalb der Felder vorkommt - die Tauglichkeit hängt also von den Daten ab. Ein fertiges Äquivalent zu explode() aus PHP beispielsweise habe ich aber auch schon mehrfach rumgehen sehen.
Sinspin - Mi 24.07.13 06:46
OldGrumpy hat folgendes geschrieben : |
Stößt allerdings an seine Grenzen, wenn das Trennzeichen auch innerhalb der Felder vorkommt - die Tauglichkeit hängt also von den Daten ab. Ein fertiges Äquivalent zu explode() aus PHP beispielsweise habe ich aber auch schon mehrfach rumgehen sehen. |
CSV ist ein Standard für Tabellen im Textformat und kann damit umgehen das die Trennzeichen in den Strings enthalten sein können. Mit zwei TStringList ist eine CSV Datei recht komfortabel zu lesen. TStringList verarbeitet auch großen Dateien erstaunlich schnell.
jaenicke - Mi 24.07.13 10:20
Nebenbei, in XE4 ginge das auch so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| uses System.SysUtils, System.IOUtils;
var CurrentLine: string; CurrentLineValues: TArray<string>; begin for CurrentLine in TFile.ReadAllLines('blubb.csv') do begin CurrentLineValues := CurrentLine.Split([';']); end; |
Aber ich vermute mal anhand deiner Profilangabe, dass du das nicht nutzen kannst.
Für echte CSV-Dateien ist ein entsprechender Reader aber sinnvoller.
Xion - Mi 24.07.13 10:37
Sinspin hat folgendes geschrieben : |
CSV ist ein Standard für Tabellen im Textformat und kann damit umgehen das die Trennzeichen in den Strings enthalten sein können. |
CSV kann das, aber der vorgeschlagene Algorithmus eben nicht. Zum Beispiel:
Quelltext
1:
| 1,"""Siehe da"", sagte er",14 |
Dann kommt man nicht mehr weit, wenn man nur bis zum nächsten Komma kopiert ;)
Es hängt natürlich ganz davon ab, woher diese CSV kommt, ob sowas überhaupt vorkommt. Sind alle Spalten z.B. Integer, dann sollte es keine Probleme damit geben. Da die Zeilen aber gegen jeden Standard durch ";" getrennt werden, vermute ich, dass da eine Excel-Tabelle dahinter steckt.
Man bräuchte wohl so eine Art Zustandsmaschine. Lese bis zum nächsten Trennzeichen oder ". Wenn " gelesen und es folgt noch eins, dann wird es durch ein " ersetzt. Sonst beginnt hier ein String und endet erst beim nächsten einfachen ", Trennzeichen dazwischen sind also zu ingorieren. Immer wenn man dann ein Trennzeichen gefunden hat, schneidet man das Stück ab und gibt es zurück.
Wenn man Typen kennt, kann man die gleich prüfen und eine vernünftige Fehlerbehandlung durchführen.
Wenn man auf das alles verzichtet, dann sieht die einfachste Variante wohl in etwa so aus:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| var csv: TextFile; S: String; AssignFile(csv,path+'my.csv'); Reset(csv); while not EoF(csv) do begin ReadLn(csv,S); S:=S+';'; while Pos(';',S)>0 do begin Spalte := Copy(S,1,Pos(';',S)-1); S := Copy(S,Pos(';',S)+1,MaxInt); end; end; CloseFile(csv); |
MeierZwoo - Mi 24.07.13 11:57
Sinspin hat folgendes geschrieben : |
CSV ist ein Standard für Tabellen im Textformat und kann damit umgehen das die Trennzeichen in den Strings enthalten sein können. |
Wie unterscheidet dann wer (?) Trennzeichen und Trennzeichen innerhalb eines Strings?
mfg
Xion - Mi 24.07.13 13:22
Texte werden üblicherweise mit " umgeben. Bsp:
1,"Apfel",15
Steht jetzt ein Trennzeichen im String ist das kein Problem, denn es ist eindeutig, dass dieses zum String gehört:
1,"Apfel,Birne",15
Einziges Problem dabei ist, wenn ebenfalls ein " im String vorkommt, weshalb diese immer escaped werden (bei csv doppelt notiert)
Statt
1,"51° 14′ 4,2"",15
heißt es also:
1,"51° 14′ 4,2""",15
Der Parser kennt das Prinzip und weiß zum einen, dass "" nichts mit der Begrenzung des Strings zu tun hat, und dass er "" danach wieder durch " ersetzen muss.
Das ist eigentlich so üblich, wobei es scheinbar kein genormtes CSV-Format gibt. An die Anführungszeichen halten sich wohl noch die meisten, das Trennzeichen selbst ist meist verschieden. Comma Seperated Values gibt also auch mit Strichpunkt oder Leerzeichen getrennt. Und dann gibt es natürlich sehr viele Codes, die das mit den Anführungszeichen nicht richtig berücksichtigen, sowohl beim Import als auch beim Export ;)
MeierZwoo - Mi 24.07.13 18:21
.. danke. Ähnlich wie bei SQL mit den doppelten Tüddelchen innerhalb eines mit Tüddelchen umgrenzten Stringalterals.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!