![]() |
Spaltenweise auf TStringList zugreifen
Hallo,
ich habe ein StringList, die wie eine Tabelle aufgebaut ist (oben der Header und dann die Werte pro Spalte). Nun möchte ich pro Spalte eine Berechnung durchführen. Wie gehe ich da am besten spaltenweise vor? (Die einzelnen Werte in einer Zeile sind durch #9 getrennt. |
Re: Spaltenweise auf TStringList zugreifen
Je nachdem wie oft du da etwas berechnen willst. Wenn es nur einmal oder so passiert, dann kannst du die einzelnen Spalten einer Zeile mit Hilfe einer weiteren TStringList auslesen und schreiben. Dafür gibt es Delimiter und DelimitedText zum Beispiel.
Wenn das immer wieder passieren soll, solltest du die Daten einmal auslesen in eine richtige Tabelle, z.B. ein zweidimensionales Array, dort damit arbeiten und dann wieder ggf. in die TStringList legen. |
Re: Spaltenweise auf TStringList zugreifen
Also ich muss immer wieder (alle par Sekunden) etwas berechnen. Wie lese ich die Daten denn in eine "richtige" Tabelle?
|
Re: Spaltenweise auf TStringList zugreifen
Woher kommen denn die Daten? Legst du die selbst in dieses (suboptimale) Format oder hast du darauf keinen Einfluss?
Ja, wie du es machst, wie gesagt, nimm für jede Zeile eine TStringList, weise Delimiter und DelimitedText zu, dann hast du die Spalten. Diese packst du jetzt in ein zweidimensionales Array. Dessen Größe musst du natürlich vorher mit SetLength anpassen. Das ist sicher nicht die schnellste Herangehensweise, aber solange die Datenmengen nicht zu groß sind akzeptabel. |
Re: Spaltenweise auf TStringList zugreifen
Darauf habe ich keinen Einfluss. Wieso "suboptimal"?
Zitat:
|
Re: Spaltenweise auf TStringList zugreifen
Doch in der 2. Stringliste werden die Werte anhand des Trenners zu Spalten
|
Re: Spaltenweise auf TStringList zugreifen
Ach so,ich probiere es gleich mal aus.
|
Re: Spaltenweise auf TStringList zugreifen
Zitat:
Zitat:
Delphi-Quellcode:
Jetzt hast du in der TStringList drin:
MyList.Delimiter := #9;
MyList.DelimitedText = 'a'#9'b'#9'c';
Code:
Du kannst also direkt auf die Spalteninhalte zugreifen.
a
b c |
Re: Spaltenweise auf TStringList zugreifen
Zur Sicherheit würde ich noch
Delphi-Quellcode:
setzen um sicherzustellen, dass nicht weitere Trenner verwendet werden ( Leerzeichen usw.)
MyList.StrictDelimiter := True;
|
Re: Spaltenweise auf TStringList zugreifen
Ich lade also die vorhandene StringList in eine neue?
Delphi-Quellcode:
Nun will ich ab Zeile 0 bis count-1 der vorhandenen Datei die Zeilen als spalten in die ZwischenSpeicher StringList speichern.
ZwischenSpeicher.LoadFromFile(VorhandeneDatei);
Delphi-Quellcode:
Nun noch in die neue Datei laden
ZwSpeicher.Delimiter := #9;
for i := 1 to Sek.Count-1 do ZwSpeicher.DelimitedText := Sek.Strings[i];
Delphi-Quellcode:
Aber irgendwas scheint da nicht zu stimmen. Ich habe nur die erste Zeile als Spalte.Und mehr kommt da nicht
ZwSpeicher.SaveToFile(TestDatei);
|
Re: Spaltenweise auf TStringList zugreifen
Klar in der 2. Stringliste befindet sich immer nur eine Zeile.
|
Re: Spaltenweise auf TStringList zugreifen
Ich denke du willst da nur etwas berechnen. Was hat denn jetzt plötzlich die Speicherung in einer Datei für einen Sinn? :gruebel:
Ich sehe bei den Variablennamen gerade nicht mehr durch. Was du machen musst ist in StringList A die Datei zu laden. Dann gehst du deren Zeilen durch. Für jede Zeile legst deren Inhalt in DelimitedText von StringList B, dann hast du die Spalten der Zeile in den Strings von StringList B. Du kannst also jetzt dort die Spalten durchgehen. Danach gehst du zur nächsten Zeile. Was du da jetzt mir ZwischenSpeicher, ZwSpeicher und Sek machst, da sehe ich nicht durch. Du lädst in ZwischenSpeicher und liest dann in der Schleife aus Sek in ZwSpeicher? :gruebel: |
Re: Spaltenweise auf TStringList zugreifen
Zitat:
Mein Fehler sorry:
Delphi-Quellcode:
ZwSpeicher.Delimiter := #9;
for i := 1 to VorhandeneDatei.Count-1 do ZwSpeicher.DelimitedText := VorhandeneDatei.Strings[i]; |
Re: Spaltenweise auf TStringList zugreifen
Zitat:
Naja, da du ja anscheinend keinen kompletten Code posten willst, kann ich da auch nicht viel zu sagen außer dass du anscheinend nix mit den Spalten machst... Hier mal nen kleines Beispiel (ungetestet):
Delphi-Quellcode:
var
FileContents, LineCols: TStringList; i, j: Integer; begin FileContents := TStringList.Create; try FileContents.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'TestFile.txt'); LineCols := TStringList.Create; try LineCols.Delimiter := #9; LineCols.StrictDelimiter := True; for i := 0 to Pred(FileContents.Count) do begin LineCols.DelimitedText := FileContents[i]; for j := 0 to Pred(LineCols.Count) do ShowMessage('Zeile ' + IntToStr(i) + ', Spalte ' + IntToStr(j) + ': ' + LineCols[j]); end; finally LineCols.Free; end; finally FileContents.Free; end; |
Re: Spaltenweise auf TStringList zugreifen
Genauso habe ich es gemacht. und nun habe ich aus der zeile:
27.07.2009 09:32:55 0,0 800,0 0,0 -30,0 die spalte : 27.07.2009 09:32:55 0,0 800,0 0,0 -30,0 gewonnnen. Nochmal zu meinem Problem : Meine Ursprungsdatei ist wie folgt aufgebaut : Datum Uhrzeit MW1 MW2 MW3 MW4 27.07.2009 09:32:55 0,0 800,0 0,3 -31,0 27.07.2009 09:32:58 0,1 820,0 0,3 -32,0 27.07.2009 09:33:01 0,3 805,0 0,2 -31,0 27.07.2009 09:33:04 0,7 821,0 0,7 -33,0 Nun möchte ich u.a. den Mittelwert aus der Spalte MW2 berechnen. Mit StringList kann ich aber nur Zeilenweise arbeiten und mit euren obigen Voschlägen habe ich ja auch nichts gewonnen, da ich immer nur eine Spalte zu Verfügung habe. Oder habe ich hier gerade etwas wichtiges übersehen? |
Re: Spaltenweise auf TStringList zugreifen
Wie ich schon sagte: Leg die Werte in ein zweidimensionales Array. Dort kannst du dann ja problemlos auf die Spalten zugreifen.
|
Re: Spaltenweise auf TStringList zugreifen
Also ich versuche es jetzt mit nem Array
Delphi-Quellcode:
und dem Code :
var StringArray: array of array of string;
Zeilenanzahl, Spaltenanzahl : integer
Delphi-Quellcode:
Allerdings möchte ich den Header aus der Sek StringList gar nicht erst als DelimitedText im ZwSpeicher haben. Wie umgehe ich das?ZwSpeicher := TStringList.Create; Sek := TStringList.Create; begin ZwSpeicher.Delimiter := #9; ZwSpeicher.DelimitedText := Sek.Strings[Sek.Count-1]; //um die Spaltenanzahl zu bestimmen Spaltenanzahl := ZwSpeicher.Count; Zeilenanzahl := Sek.Count; //für die Zeilenanzahl Setlength(StringArray,Spaltenanzahl,Zeilenanzahl); for s := 0 to Spaltenanzahl-1 do // jetzt möchte ich die Werte der Zeilen ins Array schreiben begin StringArray[s,0] := ZwSpeicher.Strings[s]; end; end; |
Re: Spaltenweise auf TStringList zugreifen
Ich finde es wäre viel einfacher von der Handhabung deine Daten pro Zeile in Objekte zu schreiben und diese Objekte in einer TObjectList zu verwalten. Dieses auf Teufel komm raus mit Strings rumhantieren ist echt sehr suboptimal.
Delphi-Quellcode:
Dann kannst du auch simpel Mittelwertberechnungen durchführen.type TMyDataObject = class public Datum: TDateTime; Wert1: float; Wert2: int; usw. end;
Delphi-Quellcode:
Auch jede andere Funktionalität lässt sich ab diesem Zeitpunkt modular einbauen.function BerechneMittelwertVonWert1(): float; var i, anzahlElemente: integer; gesamt: float; begin gesamt = 0; anzahlElemente := myObjectList.Count; for i = 0 to anzahlElemente-1 do begin gesamt := gesamt + TMyDataObject(myObjectList).Wert1; end result := gesamt/anzahlElemente; end; |
Re: Spaltenweise auf TStringList zugreifen
Zitat:
Zweitens: Du erzeugst Sek neu. Meinst du, dass Sek.Count etwas anderes als 0 sein kann direkt danach? Was wird also Sek.Strings[Sek.Count-1] sein... (usw.) |
Re: Spaltenweise auf TStringList zugreifen
Habe es jetzt ersteinmal folgendermaßen zu lösen versucht (ohne Berechnung):
Delphi-Quellcode:
Funktioniert an sich ganz gut, aber irgendetwas läuft da noch schief. Kommt eine neue Zeile in der 3SekDatei hinzu wird die im ZwSpeicher zu einer Spalte und sollte von dort ins Array und somit in die Test.txt geschrieben werden...In die Test.txt wird aber immer nur die neue Zeile geschrieben und zwar so oft, wie Zeilen in der 3SekDatei vorhanden sind.Die vorherigen verschwinden. Was mache ich falsch?
procedure ZehnMinTimerEvent(Sender: TObject);
var Sek, Min, ZwSpeicher : TStringList; DreiSek, ZehnMin, temp1, temp2 : string; Spaltenanzahl, Zeilenanzahl,z,s : integer; StringArray: array of array of string; TestDatei : TFileStream; begin DreiSek := extractfilepath(application.exename)+'3sek_'+Kennung+'.txt'; ZehnMin := extractfilepath(application.exename)+'10min_'+Kennung+'.txt'; TestDatei := TFileStream.Create(ExtractFilePath(application.exename)+'test.txt', fmCreate); Sek := TStringList.Create; Min := TStringList.Create; ZwSpeicher := TStringList.Create; try Sek.LoadFromFile(DreiSek); Min.LoadFromFile(ZehnMin); temp1 := Sek.Strings[Sek.Count-1]; temp2 := Min.Strings[Min.Count-1]; while Min.Count >= 2 do //maximal 1 Zeile + Header Min.Delete(1); if temp1 <> temp2 then ZwSpeicher.Delimiter := #9; if Sek.Count >= 2 then begin ZwSpeicher.DelimitedText := Sek.Strings[Sek.Count-1]; Spaltenanzahl := ZwSpeicher.Count-2; //ohne Datum und Uhrzeit Zeilenanzahl := Sek.Count-1; //ohne Header Setlength(StringArray,Spaltenanzahl,Zeilenanzahl); for z := 0 to Zeilenanzahl-1 do begin; for s := 0 to Spaltenanzahl-2 do begin StringArray[s,z] := ZwSpeicher.Strings[s+2]; Temp := (StringArray[s,z]) + ';'; TestDatei.Write(PChar(Temp)^,Length(Temp)); end; Temp := (StringArray[s,z]) + #13#10; TestDatei.Write(PChar(Temp)^,Length(Temp)); end; end; end; finally TestDatei.Free; ZwSpeicher.Free; Min.Free; Sek.Free; end; end; |
Re: Spaltenweise auf TStringList zugreifen
Zitat:
Zitat:
|
Re: Spaltenweise auf TStringList zugreifen
Aber alle 3 Sekunden wird ja geschaut ob ne neue Zeile existiert,wenn ja, dann wird die in ZwSpeicher als Spalte geschrieben und ins Array übertragen. Dann sollte doch bei der ersten vorhandenen Zeile ein Array (ZwSpeicher.Count-2,1 entstehen). Und wenn nun die 2. zeile hinzukommt, dann soll die ans Array angehängt werden. Und so weiter. Wo liegt denn da bloß mein Denkfehler? :wall:
|
Re: Spaltenweise auf TStringList zugreifen
Du hängst doch aber nix an, sondern gehst in der zitierten äußeren Schleife alle Zeilen durch und schreibst die Zeile überall hinein...
|
Re: Spaltenweise auf TStringList zugreifen
Ja, aber wie hänge ich das denn an? Ich hab keinen Plan mehr :gruebel:
|
Re: Spaltenweise auf TStringList zugreifen
Naja, ich würde sagen die Größe setzen ist schon einmal eine gute Idee, aber wie wäre es, wenn du danach auch wirklich nur in die letzte Zeile etwas schreibst? :gruebel:
|
Re: Spaltenweise auf TStringList zugreifen
Aber bei TFileStream gibts doch nicht so was wie count oder? ich weiß im mom echt nicht wie ich das machen soll
|
Re: Spaltenweise auf TStringList zugreifen
Was hat das damit zu tun? Es geht doch um das Array, in das zu immer wieder das selbe schreibst...
Statt deiner beiden Schleifen reicht es doch, wenn du in die letzte Zeile schreibst...
Delphi-Quellcode:
for s := 0 to Spaltenanzahl - 2 do
StringArray[s, Zeilenanzahl - 1] := ZwSpeicher.Strings[s + 2]; |
Re: Spaltenweise auf TStringList zugreifen
Hatte ich eben auch in ähnlericher Form schon.
Delphi-Quellcode:
z := Zeilenanzahl-1;
begin; for s := 0 to Spaltenanzahl-2 do begin StringArray[s,Zeilenanzahl-1] := ZwSpeicher.Strings[s+2]; Temp := (StringArray[s,z]) + ';'; TestDatei.Write(PChar(Temp)^,Length(Temp)); end; Temp := (StringArray[s,z]) + #13#10; TestDatei.Write(PChar(Temp)^,Length(Temp)); end; |
Re: Spaltenweise auf TStringList zugreifen
Statt irgendwas in eine Textdatei zu schreiben, solltest du lieber im Debugger direkt schauen was da passiert. :roll:
Was passiert denn, wenn du es so machst? Wie wäre es, wenn du ein kleines Testprojekt anhängst? |
Re: Spaltenweise auf TStringList zugreifen
Delphi-Quellcode:
Wie mache ich das? (Entschuldige,aber ich bin wirklich noch sehr neu) :pale:
Statt irgendwas in eine Textdatei zu schreiben, solltest du lieber im Debugger direkt schauen was da passiert
|
Re: Spaltenweise auf TStringList zugreifen
Hallo,
mit der Taste F7 kannst Du Dein Programm im Einzelschrittmodus ausführen. Befindet sich deine Maus im Codeeditor über einer Variablen wird Dir der aktuelle Inhalt angezeigt. Das Tutorial von MaBuSe kann ich Dir empfehlen: ![]() |
Re: Spaltenweise auf TStringList zugreifen
Das wusste ich ja doch schon :-D Aber danke nochmal. Nuhn ist aber das Problem mit F7, dass er ja das komplette Programm durchlaufen will.Mich interessiert doch aber nur die aktuelle Unit.- Da sitz ich ja morgen noch und druck F7 :gruebel:
|
Re: Spaltenweise auf TStringList zugreifen
Was spricht den gegen das Setzen eines Breakpoints?
|
Re: Spaltenweise auf TStringList zugreifen
Hab ich schon probiert,aber irgendwie ignoriert er diesen. Zumindestens fängt er trotz breakpoint immer wieder von vorne an
|
Re: Spaltenweise auf TStringList zugreifen
Ja, wo soll das Programm sonst anfangen? Das ist ein Haltepunkt, also ein Punkt zum Anhalten. Heißt: Das Programm hält an, wenn es da ankommt.
Also setze den Haltepunkt, starte das Programm mit F9. Wenn jetzt das Programm dort ankommt, meldet sich Delphi und du kannst schrittweise durchgehen. Dabei würde ich eher F8 empfehlen, da du dann nicht in Funktionsaufrufe hineingehst. (Das musst du dann entscheiden was du willst.) Du kannst auch mehrere Haltepunkte setzen, dann kannst du F9 drücken, dann läuft das Programm bis zum nächsten Haltepunkt. Wenn das Programm gerade angehalten ist, kannst du mit Strg + F7 die markierte Stelle des Quelltextes, z.B, eine Variable auswerten und hineinschauen. |
Re: Spaltenweise auf TStringList zugreifen
Tausden dank. Ich poste mal den Code:
Delphi-Quellcode:
Ich denke, es sollte so fast stimmen. Allerdings wird immernoch nur eine neue zeile in die datei geschrieben und nicht wie gewollt die neue unter die alte gehängt
procedure ZehnMinTimerEvent(Sender: TObject);
var Sek, Min, ZwSpeicher : TStringList; DreiSek, ZehnMin,Temp, temp1, temp2, DatUhr, Datei : string; TabPos, Spaltenanzahl, Zeilenanzahl,s, z : integer; StringArray: array of array of string; TestDatei : TFileStream; begin DreiSek := extractfilepath(application.exename)+'Mom3sek_'+Kennung+'.txt'; ZehnMin := extractfilepath(application.exename)+'Mom10min_'+Kennung+'.txt'; TestDatei := TFileStream.Create(ExtractFilePath(application.exename)+'test.txt', fmCreate or fmOpenReadWrite); Sek := TStringList.Create; Min := TStringList.Create; ZwSpeicher := TStringList.Create; try Sek.LoadFromFile(DreiSek); Min.LoadFromFile(ZehnMin); temp1 := Sek.Strings[Sek.Count-1]; //letzte Zeile der 3SekDatei temp2 := Min.Strings[Min.Count-1]; //letzte Zeile der 10MinDatei while Min.Count >= 2 do //maximal 1 Zeile + Header Min.Delete(1); if temp1 <> temp2 then begin TabPos := posEx(#9,temp1,13); if TabPos <> 0 then begin DatUhr := Copy(temp1,0,TabPos); //Datum und Uhrzeit einfügen ZwSpeicher.Delimiter := #9; if Sek.Count >= 2 then //ab der 1.Zeile + Header anfangen begin ZwSpeicher.DelimitedText := Sek.Strings[Sek.Count-1]; Spaltenanzahl := ZwSpeicher.Count-2; //ohne Datum und Uhrzeit Zeilenanzahl := Sek.Count-1; //ohne Header Setlength(StringArray,Spaltenanzahl,Zeilenanzahl); begin z := Zeilenanzahl-1; begin; for s := 0 to Spaltenanzahl-2 do begin StringArray[s,z] := ZwSpeicher.Strings[s+2]; Temp := (StringArray[s,z]) + ';'; TestDatei.Write(PChar(Temp)^,Length(Temp)); end; StringArray[Spaltenanzahl-1,z] := ZwSpeicher.Strings[ZwSpeicher.Count-1]; Temp := (StringArray[Spaltenanzahl-1,z]) + #13#10; TestDatei.Write(PChar(Temp)^,Length(Temp)); end; end; end; Min.Add(DatUhr); end; Min.SaveToFile(ZehnMin); end; finally TestDatei.Free; ZwSpeicher.Free; Min.Free; Sek.Free; end; end; |
Re: Spaltenweise auf TStringList zugreifen
Nach dem Öffnen der Datei, den Dateizeiger ans Ende setzen?
Delphi-Quellcode:
Seek nochmal in der Hilfe nachschauen, hab' es aus der Erinnerung raus geschrieben.
TestDatei.Seek(0, soFromEnd);
Muss aber zugeben, das ich den Thread jetzt nur überflogen habe und evtl. am Thema vorbeiposte :oops: |
Re: Spaltenweise auf TStringList zugreifen
:thumb: Danke, das wars. Klappt fast perfekt. Nochmal danke für eure geduld. :thumb:
|
Re: Spaltenweise auf TStringList zugreifen
Eine kleine Frage hätte ich noch.
Delphi-Quellcode:
Es wird ja alle 3 Sekunden eine neue Zeile angehängt.Allerdings soll das nur geschehen, wenn sich die Zeilenanzahl verändert hat. Wie kann ich das Prüfen?
z := Zeilenanzahl-1;
begin; for s := 0 to Spaltenanzahl-2 do begin StringArray[s,z] := ZwSpeicher.Strings[s+2]; Temp := (StringArray[s,z]) + ';'; TestDatei.Write(PChar(Temp)^,Length(Temp)); end; StringArray[Spaltenanzahl-1,z] := ZwSpeicher.Strings[ZwSpeicher.Count-1]; Temp := (StringArray[Spaltenanzahl-1,z]) + #13#10; TestDatei.Write(PChar(Temp)^,Length(Temp)); end; |
Re: Spaltenweise auf TStringList zugreifen
Die Größe der Datei / die Anzahl der Zeilen in einem Feld oder einer Eigenschaft speichern und bei einer Änderung den Code durchführen.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:28 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz