Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Textdatei (txt) in Stringgrid einlesen (https://www.delphipraxis.net/143030-textdatei-txt-stringgrid-einlesen.html)

Pascall 8. Nov 2009 14:20


Textdatei (txt) in Stringgrid einlesen
 
Hey

Ich will etwas in einen Stringgrid einlesen aus einer Textdatei (*.txt).
Es geht darum Buchstaben + der zugehörigen Häufigkeit einzulesen. Dabei ist es wichtig, dass der Häufigste Buchstabe mit der Häufigkeit oben steht.
Die Häufigkeit und der Buchstabe sollen aber in getrennte Zeilen.

Vielleicht könnte man eine Textdatei nach diesem Muster erstellen:

A(17%)
B(2%)
C(4,5%)
...

Dabei die Buchstaben in das eine, die Zahlen in das andere einlesen. Was vermutlich viel aufwändiger wäre, dann noch alles nach größe zu sortieren. Daher ist es wohl besser die Zahlen schon in der Textdatei geordnet vorzuliegen zu haben.

Wichtig ist mir hierbei auch, dass ich gerne Denkanstöße annehme, jedoch nichts vorprogrammiert haben will. Ich weiß gar nicht wie man erwarten kann, wenn man sich Programmieren selber beibringt, gesagt zu bekommen: Benutze das und das.
Wenn man dann nochmal nachfragt heißt es gleich: Musst du schon selber machen. Den Lerneffekt verstehe ich dabei gar nicht. (War nicht hier)

Vielen Dank

Pascall

alzaimar 8. Nov 2009 15:08

Re: Textdatei (txt) in Stringgrid einlesen
 
Teile die Aufgabe auf:
1. Textdatei einlesen und Buchstaben zählen. Ausgabe z.B. mit WriteLn als konsolenanwendung.
2. Die Ausgabe (also das Ergebnis) sortieren.
2. Wenn das Ergebnis stimmt, dann die Ergebnisse in ein Stringgrid schreiben. Dazu musst du dann ein neues Projekt starten, kannst aber die Ergebnisse (den Code) aus 1 und 2 verwenden...

Luckie 8. Nov 2009 16:20

Re: Textdatei (txt) in Stringgrid einlesen
 
Was ist denn jetzt dein konkretes Problem? Was hast du schon an Code? Was erwartest du jetzt von uns?

p80286 9. Nov 2009 15:14

Re: Textdatei (txt) in Stringgrid einlesen
 
Hallo Pascall,

Ich würde es so lösen:
1) array [0..255] of integer
wobei jede Array-Zelle für einen Buchstabe/Zeichen steht.
mit 0 initialisieren.

2) Textdatei Zeichen für Zeichen lesen und das Zeichen als Index des Arrays verwenden und dann inc(a[ord(Zeichen)],1);
(natürlich gepuffert alles andere wäre zu langsam)

3) Im Stringgrid die erste Spale mit den Zeichen vorbelegen, in der zweiten Spalte die im Array gespeicherten Zählungen.

Gruß
K-H

Uwe Raabe 9. Nov 2009 15:51

Re: Textdatei (txt) in Stringgrid einlesen
 
Also, habe ich jetzt die Frage falsch verstanden?

Ich interpretiere das so, daß er den Inhalt des Stringgrids aus einer Textdatei laden will, in der die einzelnen Buchstaben zusammen mit ihrer Häufigkeit stehen. Wie diese Textdatei zustande kommt, hat damit gar nichts zu tun. Vielleicht gibt es ja solche Buchstabenhäufigkeitsdateien für verschiedene Sprachen oder sonstige Kriterien bereits.

Man könnte die Textdatei einfach nach dem Name=Value Prinzip aufbauen, einfach in eine Stringlist laden und daraus dann das Stringgrid füllen.

Delphi-Quellcode:
 
lst := TStringList.Create;
try
  lst.LoadFromFile(FileName);
  for I := 0 to lst.Count - 1 do begin
    StringGrid[0, I] := lst.Names[I];
    StringGrid[1, I] := lst.ValueFromIndex[I];
  end;
finally
  lst.Free;
end;

Pascall 10. Nov 2009 14:43

Re: Textdatei (txt) in Stringgrid einlesen
 
Hey

Folgendes:
Ich habe einen Stringgrid und will dort eine Textdatei einlesen.
Die Textdatei soll etwa so aussehen:


E (17,7)
A (35,7)
X (0,03)
B (33,6)


Dabei will ich die Buchstaben in die 4 Zeile einlesen und die Zahlen entsprechen passend in die 5. Zeile. Danach sollen Buchstaben + Zahlen sortiert werden (nach den Zahlen, aber Buchstaben müssen natürlich dabei bleiben) Das habe ich aber schon.

Mir fehlt nur noch das einlesen

Pascall

@ Uwe: Deinen Ansatz verstehe ich leider nicht, sorry: Loadfromfile ist klar, mit try und finally habe ich noch nie gearbeitet
@ p80286: Das mit dem puffern interessiert mich, ist das einfach zu programmieren? Das bräuchte ich nämlich auch noch für eine andere Sache...

p80286 10. Nov 2009 16:14

Re: Textdatei (txt) in Stringgrid einlesen
 
Hallo pascall,

das mit Try finally funktioniert so, daß wenn ein Fehler zwischen try und finally auftritt, die Verarbeitung sofort zur Anweisung nach finally springt.
In Uwes Beispiel befindet sich vor Finally der "Leseabschnitt" und hinter finally der "Aufräumabschnitt" der auf jeden Fall ausgeführt werden sollte. Man könnte darüber streiten ob das unbedingt notwendig ist, ein Fehler ist es aber auf keinen Fall, da dann sicher gestellt ist, daß z.B. lst wieder aus dem Speicher verschwindet.

[Edit]
wenn Die Daten so erfasst sind, wie Du beschrieben hast, dann kommst Du mit CommaText oder Value nicht weiter, dann mßt Du mit pos('(',...) die eingelesenen Zeilen auseinander nehmen.
[/Edit]

"Puffern":

Delphi-Quellcode:
const
  maxpuff = $FFFF;
var
  puffer : array [0..maxPuff] of byte;
  fs    : tfilestream;

...

fs:=tfilestream.create(MyFilename,myAttributes);
repeat
  gelesen:=fs.read(puffer,sizeof(puffer));
  for i:=0 to gelesen do
   //....verarbeite puffer[i] .........
until gelesen<>sizeof(puffer);
fs.free;
So in etwa sieht eine solche Leseroutine aus. Wobei für Dich der maxPuff der interessanteste Teil ist, da sollte man nicht zu sparsam sein. Puffer kann allerdings auch ein array of byte, oder array of char oder ... sein.
wichtig ist hier nur, daß Du das nicht zu klein wählst.


Gruß
K-H

DeddyH 10. Nov 2009 16:45

Re: Textdatei (txt) in Stringgrid einlesen
 
Ich würde mir einen Record oder noch besser eine Klasse deklarieren, die die zusammenhängenden Daten beinhaltet. Dann die Textdatei einlesen, die einzelne Zeile parsen und dem Record/der Klasse die Einzelwerte zuweisen. Die Records/Objekte werden dann in einer Liste verwaltet, sortiert und im StringGrid ausgegeben. Hier das Ganze einmal in Code gepackt:
Delphi-Quellcode:
uses math;

//Deklaration der Klasse
type
  TDatensatz = class
  private
    FBuchstabe: Char;
    FZahl: Double;
  public
    property Buchstabe: Char read FBuchstabe write FBuchstabe;
    property Zahl: Double read FZahl write FZahl;
  end;

//Sortierfunktion
function CompareFunc(Item1, Item2: Pointer): integer;
begin
  if SameValue(TDatensatz(Item1).Zahl, TDatensatz(Item2).Zahl) then
    Result := 0
  else if TDatensatz(Item1).Zahl < TDatensatz(Item2).Zahl then
    Result := -1
  else
    Result := 1;
end;

procedure TfrmStringGridDemo.Button1Click(Sender: TObject);
const Pfad = 'C:\Test\Test.txt'; //nur zum Testen hartkodiert
var aObject: TDatensatz;
    aList: TStringlist;
    i, FirstBracket, SecondBracket: integer;
    s: string;
begin
  //evtl. bereits enthaltene Objekte löschen
  FObjects.Clear;

  //Stringliste erzeugen und aus Datei einlesen
  aList := TStringlist.Create;
  try
    aList.LoadFromFile(Pfad);

    //Dafür sorgen, dass genügend Zellen im StringGrid verfügbar sind
    if (StringGrid1.ColCount - StringGrid1.FixedCols) < aList.Count then
      StringGrid1.ColCount := aList.Count + StringGrid1.FixedCols;
    if (StringGrid1.RowCount - StringGrid1.FixedRows) < 5 then
      StringGrid1.RowCount := StringGrid1.FixedRows + 5;

    //Datei zeilenweise auswerten, Objekt erzeugen, Werte zuweisen
    for i := 0 to aList.Count - 1 do
      begin
        aObject := TDatensatz.Create;
        if trim(aList[i]) <> '' then
          aObject.Buchstabe := trim(aList[i])[1];
        FirstBracket := Pos('(',aList[i]);
        SecondBracket := Pos(')',aList[i]);
        s := Copy(aList[i],FirstBracket + 1, SecondBracket - FirstBracket - 1);
        aObject.Zahl := StrToFloatDef(s,0);

        //... und der Liste hinzufügen
        FObjects.Add(aObject);
      end;

    //Liste sortieren
    FObjects.Sort(@CompareFunc);
    StringGrid1.Rows[StringGrid1.FixedRows + 3].BeginUpdate;
    StringGrid1.Rows[StringGrid1.FixedRows + 4].BeginUpdate;
    try
      //... und Werte in der StringGrid ausgeben
      for i := 0 to FObjects.Count - 1 do
        begin
          StringGrid1.Cells[StringGrid1.FixedCols + i,StringGrid1.FixedRows + 3] := TDatensatz(FObjects[i]).Buchstabe;
          StringGrid1.Cells[StringGrid1.FixedCols + i,StringGrid1.FixedRows + 4] := FloatToStr(TDatensatz(FObjects[i]).Zahl);
        end;
    finally
      StringGrid1.Rows[StringGrid1.FixedRows + 3].EndUpdate;
      StringGrid1.Rows[StringGrid1.FixedRows + 4].EndUpdate;
    end;
  finally
    //Stringliste wieder freigeben
    aList.Free;
  end;
end;

//mit dem Formular Objektliste erzeugen
procedure TfrmStringGridDemo.FormCreate(Sender: TObject);
begin
  FObjects := TObjectList.Create;
end;

//und am Ende entsorgen
procedure TfrmStringGridDemo.FormDestroy(Sender: TObject);
begin
  FObjects.Free;
end;

p80286 10. Nov 2009 17:00

Re: Textdatei (txt) in Stringgrid einlesen
 
@DeddyH

Ist die frühe Festlegung von RowCount und ColCount notwendig oder Dein pers. Stil?

Gruß
K-H

Pascall 10. Nov 2009 17:03

Re: Textdatei (txt) in Stringgrid einlesen
 
@DeddyH: So werde ich es vermutlich machen, danke

@ p80286: Danke, dass mit dem try + finally habe ich kapiert. Was sinnvolles neues gelernt =). Jedoch das mit dem Puffern ist wohl eine Nummer zu hoch für mich, da blicke ich überhaupt nicht durch. Trotzdem vielen Dank für den Versuch.

Bin ein Pascal Anfänger und das reicht mir auch erst Mal. Wenn ich die Schule beendet habe werde ich mich mit C++ vertraut machen und ich denke dafür reicht mein bisheriges kleines Wissen schon aus. Ein wirklich sehr nettes Forum hier, vielen Dank für eure ganze Hilfe.
Ich wette es war nicht das letzte Mal, dass ich hier geschrieben habe =)

implementation 10. Nov 2009 17:15

Re: Textdatei (txt) in Stringgrid einlesen
 
Zitat:

Zitat von Pascall
Bin ein Pascal Anfänger und das reicht mir auch erst Mal. Wenn ich die Schule beendet habe werde ich mich mit C++ vertraut machen und ich denke dafür reicht mein bisheriges kleines Wissen schon aus. Ein wirklich sehr nettes Forum hier, vielen Dank für eure ganze Hilfe.
Ich wette es war nicht das letzte Mal, dass ich hier geschrieben habe =)

So viel anders ist C++ nun auch wieder nicht. Das Vorgehen ist schliesslich das gleiche...

DeddyH 10. Nov 2009 17:20

Re: Textdatei (txt) in Stringgrid einlesen
 
Zitat:

Zitat von p80286
@DeddyH

Ist die frühe Festlegung von RowCount und ColCount notwendig oder Dein pers. Stil?

Gruß
K-H

Sobald ich auf eine bestimte Zelle zugreife, muss ich ja sicher sein, dass die auch da ist, meinst Du nicht? Gut, ich hätte das auch nach dem Befüllen der Objektliste machen können, aber das sollte ja nicht die große Rolle spielen.

p80286 10. Nov 2009 17:33

Re: Textdatei (txt) in Stringgrid einlesen
 
@DeddyH

Zitat:

Zitat von DeddyH
Sobald ich auf eine bestimte Zelle zugreife, muss ich ja sicher sein, dass die auch da ist, meinst Du nicht?

Bei mir klappt es immer mit
Delphi-Quellcode:
 for i:=0 to xxxx.count-1 do
  .......
 yyy.rowcount:=xxxx.count+1;
wichtig ist nur daß RowCount nicht kleiner 2 wird, damit die "grauen Überschriften" nicht verschwinden.
Mein Vorgehen scheint nicht logisch aber es klappt. Oder hab ich nur Glück gehabt?
Ich meine mich erinnern zu können, daß RowCount für die sichtbaren/anzeigbaren Zeilen steht, bin mir aber nicht sicher.

(über den Speicher, den man da verbraten kann mach ich mir jetzt mal keine Gedanken)

Gruß
K-H

DeddyH 10. Nov 2009 17:37

Re: Textdatei (txt) in Stringgrid einlesen
 
Wenn ich von vornherein weiß, wieviele Zeilen/Spalten ich benötige, ist die Erhöhung innerhalb einer Schleife IMHO suboptimal. Und für die "grauen" Spalten/Zeilen habe ich ja FixedRows bzw. FixedCols mit berücksichtigt :zwinker:

p80286 10. Nov 2009 17:41

Re: Textdatei (txt) in Stringgrid einlesen
 
Welche Schleife?
so ists deutlicher:
Delphi-Quellcode:
for i:=0 to xxxx.count-1 do
begin
  .......
end;
yyy.rowcount:=xxxx.count+1;
und wenn RowCount<2 ist, dann klappt das mit den FixedRows nicht mehr. (D2006 und D7)
Gruß
K-H

DeddyH 10. Nov 2009 17:45

Re: Textdatei (txt) in Stringgrid einlesen
 
Ach, so war das gemeint. OK, dann spielt es keine Rolle, wann man RowCount/ColCount setzt, Hauptsache, vor dem ersten indizierten Zugriff. Und ja, Du hast recht, nur fixe Spalten oder Zeilen akzeptiert das Dingen nicht. Aber in meinen Augen ist das eh nicht die dollste Komponente der VCL, daher meide ich sie nach Möglichkeit.

Lannes 10. Nov 2009 19:15

Re: Textdatei (txt) in Stringgrid einlesen
 
Hallo,

und ich bevorzuge sie :wink:

Es ist kein Problem das Array Cells mit Werten zu belegen auch wenn RowCount/ColCount kleiner als der Index für Cells ist.
Auch ein Zugriff auf die Inhalte des Cells-Array verursacht keine Zugriffsverletzungen.

Delphi-Quellcode:
Grid.Cells[Grid.ColCount + 1000, Grid.RowCount + 1000] := 'Test';
Showmessage(Grid.Cells[Grid.ColCount + 1000, Grid.RowCount + 1000]);
//erst wenn man was selectieren will, knallt es
Grid.Row := Grid.RowCount + 1000;// "Gitterindex außerhalb"
Grid.Cells[c,r], Grid.Cols[c] und Grid.Rows[r] sind unabhängig vom dem durch ColCount/RowCount definierten Bereich.


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