Entwickler-Ecke

Dateizugriff - txt Datei: Bis zu Zeichen auslesen


Thunfisch - Do 23.06.11 11:22
Titel: txt Datei: Bis zu Zeichen auslesen
Hallo :) (ist glaube ich mein erster Post)


Ich habe Informatik in der Schule im 4. Jahr aber mache erst seit einem 3/4 Jahr Delphi.
Wir sollten uns gegen Schluss des Schuljahres ein Projekt aussuchen, was wir dann selbst verwirklichen.
Ich habe mir einen Vokabeltrainer vorgenommen :)
Da ich (grade mal) mit txt-dateien umgehen kann, speicher ich die eingegebenen Vokabeln in einer txt-Datei.


Mein Problem besteht beim Auslesen:

Ich möchte, dass man die ausgelesene Vokabel zum Abfragen benutzen kann sowie dass man aus den ganzen Vokablen bspw. 20 random ausliest.

Meine Lösung dafür wäre, dass ich alle Vokabeln auslese und dann in ein Array speicher. Aber wie ich die einzelnen Eigenschaften der Vokabeln abspeichern kann ist mir ein Rätsel.


Hier nochmal ein Beispiel aus meiner Vokabel.txt :


1#fisch#fish#chicken
2#Haus#House#House
3#Haus#House#House
4#Hallo#hi#hi
5#Brother#Bruder#Bruder
6# Frieden#Peace# war
7#Mutter#mother#UNBEKANNT
8#Maus#Mouse#Mouse
9#Auto#Car#



ID;#;Deutsch;#;Englisch1;#;Englisch2

# soll als Trennzeichen dienen


MFG Thunfisch


PS: ich benutze delphi 6 !


MaxWurzel - Do 23.06.11 11:38

Du kannst z.B. ein record benutzen

Delphi-Quelltext
1:
2:
3:
4:
5:
type Vokabel = record
       deutsch: string;       
       englisch1: string;
       englisch2: string;
end;



[quote="[user]5#Brother#Bruder#Bruder
ID;#;Deutsch;#;Englisch1;#;Englisch2
quote]
?


Thunfisch - Do 23.06.11 11:44

Jo fast genau den benutze ich ;)

Aber mir gehts ja mehr ums Auslesen


Jann1k - Do 23.06.11 11:52

Hast du Probleme beim Auslesen der Zeilen aus deiner .txt Datei oder beim Auslesen der einzelnen Eigenschaften?

Für letzteres gibt es die Funktionen Pos und PosEx, damit kannst du in deiner Zeile nach den Trennzeichen suchen und dir dann mithilfe von Copy die passenden Stringteile auslesen lassen.


MaxWurzel - Do 23.06.11 12:08

Du kannst die txt-Datei in eine Stringlist laden

Delphi-Quelltext
1:
2:
3:
4:
var vokabelliste: TStringlist;

vokabelliste := TStringlist.Create;
vokabelliste.LoadFromFile(xxx.txt);

und dann auf die Zeilen mit

Delphi-Quelltext
1:
vokabelliste.Strings[i]                    

zugreifen.


Webo - Do 23.06.11 12:36

Also, wenn es es ums Auslesen geht werfe ich mal ein paar Begriffe in den Raum:

Einlesen kannst du die Datei wie user profile iconMaxWurzel schreibt, die Wörter dann wie folgt.

(Situation: Du hast z.B. die erste Zeile der Textdatei in einen String s geladen)

- s[i] gibt dir das Zeichen an i-ter Position zurück
- pos('ch',s) gibt dir die Position des ersten Vorkommens von "ch" wieder, wenn es in s vorhanden ist (-1 wenn nicht)
- posex('ch', s, 3) wie pos, jedoch sucht es erst ab Position 3
- copy(s,2,5) gibt dir den Bereich des String zwischen der Position 2 und 5 wieder (kopiert also den Bereich)

Wenn du dir damit Gedanken machst hast du genug Möglichkeiten wie du die Wörter einliest.


Thunfisch - Do 23.06.11 13:34

Super :D

Vielen Dank an euch :)
Läuft jetzt sogut wie alles


Thunfisch


Stundenplan - Do 23.06.11 15:46

user profile iconWebo hat folgendes geschrieben Zum zitierten Posting springen:
copy(s,2,5) gibt dir den Bereich des String zwischen der Position 2 und 5 wieder (kopiert also den Bereich)

Nicht ganz. ;-) Copy(s, 25) kopiert dir den Bereich ab Position 2 mit der Länge 5! :idea:

Viele Grüße,
Stundenplan.


Bergmann89 - Do 23.06.11 16:19

Hey,

als Ergänzung: dafür gibts es auch vorgefertigte Methoden. z.B. über eine Stringlist:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
var
  List: TStringList;

List := TStringList.Create;
try
  List.Delimiter := '#';
  List.DelimitedText := '1#fisch#fish#chicken';
  List[0//Zugriff auf ID
  List[1//Zugriff auf Deutsch
  {...}
finally
  List.Free;
end;


MfG Bergmann.


Webo - Do 23.06.11 16:34

user profile iconStundenplan hat folgendes geschrieben Zum zitierten Posting springen:

Nicht ganz. ;-) Copy(s, 25) kopiert dir den Bereich ab Position 2 mit der Länge 5! :idea:

Stimmt, jetzt wo du es sagst 8) Gut, dass immer wer aufpasst ...


jaenicke - Do 23.06.11 16:52

user profile iconBergmann89 hat folgendes geschrieben Zum zitierten Posting springen:
als Ergänzung: dafür gibts es auch vorgefertigte Methoden. z.B. über eine Stringlist:
Die Stringlist trennt aber auch bei Leerzeichen, wenn keine Anführungszeichen gesetzt sind. Erst bei neueren Delphiversionen gibt es dagegen StrictDelimiter, aber das kam erst mit Delphi 2006 oder so, evtl. auch schon D7. Aber bei D6, das er nutzt, gab es das auf jeden Fall noch nicht.


Thunfisch - Do 23.06.11 19:13

Habe mir grade ne neuere Version von meinem Lehrer zukommen lassen.
Die ist 7.0 - kann ich damit StrictDelimiter benutzen?


jaenicke - Do 23.06.11 19:28

Jetzt zu Hause habe ich gerade nachgeschaut, nein, wie ich schon dachte geht es da noch nicht. StrictDelimiter wurde mit Delphi 2006 eingeführt, Delphi 1-7 und 2005 kannten das noch nicht.

Es selbst zu machen ist aber ohnehin die bessere Übung. ;-)


Thunfisch - Di 28.06.11 22:21

user profile iconBergmann89 hat folgendes geschrieben Zum zitierten Posting springen:
Hey,

als Ergänzung: dafür gibts es auch vorgefertigte Methoden. z.B. über eine Stringlist:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
var
  List: TStringList;

List := TStringList.Create;
try
  List.Delimiter := '#';
  List.DelimitedText := '1#fisch#fish#chicken';
  List[0//Zugriff auf ID
  List[1//Zugriff auf Deutsch
  {...}
finally
  List.Free;
end;


MfG Bergmann.



Dazu habe ich nochmal eine Frage:

Bei  List.DelimitedText := '1#fisch#fish#chicken'; was genau muss ich da eintragen? Nimmt der diesen String dann als Muster? Oder sollte ich da Variablen eintragen? (Vok.deutsch, Vok.Id , usw.?)


Sorry wenn ich den Thread unnötigerweise pushe, aber einen neuen Thread zu erstellen erschien mir überflüssig.


Mfg Thunfisch :)


MDX - Di 28.06.11 23:18

Mhm, also für die Trennung von einer Vokabel in die "drei" Sprachen kannst du auch Explode nutzen...


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
function Explode(const Separator, S: string; Limit: Integer = 0): TStringDynArray;
var
  SepLen: Integer;
  F, P: PChar;
  ALen, Index: Integer;
begin
  SetLength(Result, 0);
  if (S = ''or (Limit < 0then Exit;
  if Separator = '' then
  begin
    SetLength(Result, 1);
    Result[0] := S;
    Exit;
  end;
  SepLen := Length(Separator);
  ALen := Limit;
  SetLength(Result, ALen);

  Index := 0;
  P := PChar(S);
  while P^ <> #0 do
  begin
    F := P;
    P := AnsiStrPos(P, PChar(Separator));
    if (P = nilor ((Limit > 0and (Index = Limit - 1)) then P := StrEnd(F);
    if Index >= ALen then
    begin
      Inc(ALen, 5); 
      SetLength(Result, ALen);
    end;
    SetString(Result[Index], F, P - F);
    Inc(Index);
    if P^ <> #0 then Inc(P, SepLen);
  end;
  if Index < ALen then SetLength(Result, Index);
end;


Thunfisch - Di 28.06.11 23:43

Das ist mir um ehrlich zu sein ein bisschen zu kompliziert :/

Da würde ich lieber die obengenannte Problemlösung nehmen ..


MDX - Di 28.06.11 23:51

Mh eigentlich ganz easy, du deklarierst einfach:


Delphi-Quelltext
1:
type TSTringdynarray = array of String;                    


Dann deklarierst du eine Variable als Array und machst dann einfach:


Delphi-Quelltext
1:
Variable:=Explode(String,'#');                    


dann hast du zum Beispiel Deutsch in Variable[0]; und Englisch1 in Variable[1];


jaenicke - Mi 29.06.11 05:55

user profile iconThunfisch hat folgendes geschrieben Zum zitierten Posting springen:
Bei  List.DelimitedText := '1#fisch#fish#chicken'; was genau muss ich da eintragen?
Den String, den du auseinander nehmen willst.

Aber wie gesagt: Es dürfen bei dieser Methode keine Leerzeichen drin vorkommen, sonst wird bei deinem Delphi dort auch getrennt.


Thunfisch - Mi 29.06.11 15:42

Es kommen keine Leerzeichen vor
Dafür habe ich schon gesorgt :D

@ Jaenicke
Kann ich da auch Tstringarray[i] eintragen?



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
function TForm1.StrToVokabelInfo(Str: String): TVokabelInfo;
// Auslesen des VokabelStrings aus der Textdatei
// + Eintragen in Temporären Record mit anschließendem Eintragen in den globalen geladenen Vokabelrecord

var temp: TVokabelInfo;
    i, j: Integer;
    tempID: String;
begin
j := 1;


for i := 1 to Length(Str) do begin
if Str[i] = '#' then Inc(j);

   if j = 1 then begin
   if Str[i] <> '#' then begin
   tempID := TempID + Str[i];
   end;
   end;


  if j = 2 then begin
  if Str[i] <> '#' then begin
     temp.Deutsch := temp.Deutsch + Str[i];
  end;
  end;

  if j = 3 then begin
  if Str[i] <> '#' then begin
     temp.Englisch := temp.Englisch + Str[i];
  end;
  end;

  end;




temp.ID := STRTOINT(tempID);

if ADMIN then
ShowMessage('Vokabel ' + IntToStr(temp.Id) + ', deutsch: ' + temp.Deutsch +  ', englisch: ' + temp.Englisch);


Kann mir einer sagen, wo da der fehler ist :D?


jaenicke - Mi 29.06.11 16:22

user profile iconThunfisch hat folgendes geschrieben Zum zitierten Posting springen:
Kann mir einer sagen, wo da der fehler ist :D?
Der Fehler ist, dass du die Fehlerbeschreibung vergessen hast. :zwinker:

Jedenfalls hat j den Wert 1. Da du den nie änderst, können die anderen if-abfragen auf j = 2 und j = 3 nie true ergeben.


Thunfisch - Mi 29.06.11 16:52

Oh mann :/
Ich schaffs einfach nicht. Immer irgendwelche komischen Fehler. Langsam verzweifle ich :(

Ich muss im Prinzip nur wissen, wie ich 1#fisch#fish sowas auslese und in einem record speichere
Also eine ganze Textdatei mit mehreren solcher Strings...


Jann1k - Mi 29.06.11 19:20

Zitat:
Immer irgendwelche komischen Fehler.


Wie jaenicke auch schon angemerkt hat: Wenn du uns nicht sagst, welche komischen Fehler bei dir auftauchen, können wir nur schlecht helfen. Der Code oben sieht korrekt aus und scheint zu funktionieren (jdf. bekomme ich die richtige showmessage ausgabe).


Thunfisch - Mi 29.06.11 19:34

wenn ich versuche die funktion aufzurufen kommt : Nicht genügend wirkliche parameter
Habe ich shcon gegoogelt und dort stand, dass man sich den quellcode nochmal ganz genau anschauen sollte


Jann1k - Mi 29.06.11 19:46

Nicht genügend wirkliche parameter, sagt doch eigentlich was da fehlt, dir fehlt ein (oder mehrere) Parameter ;) Zeig mal wie du die Funktion im Quelltext benutzt.


Thunfisch - Mi 29.06.11 19:52

Ich hab es einfach so ausprobiert :


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
procedure TForm1.b_testClick(Sender: TObject);


begin



   StrToVokabelInfo() ;

end;



Und wie kann ich eine einfache Abfrage gestalten von allen vokabeln die in der text datei liegen ?


Jann1k - Mi 29.06.11 20:00

Hast du die Funktion selbst geschrieben? In der Signatur steht doch, dass der du Funktion auch einen String als Parameter übergeben musst (dieser wird dann in ein TVokabelInfo umgewandelt). Also ungefähr so:


Delphi-Quelltext
1:
StrToVokabelInfo('12#mutig#brave') ;                    


Thunfisch - Mi 29.06.11 20:02

Und wie kann ich eine einfache Abfrage gestalten von allen vokabeln die in der text datei liegen ?

Aber kann ich da auch meine ganze vokabel list reinsetzen? also wenn ich die vorher in eine Tstringlist geladen habe


Jann1k - Mi 29.06.11 20:06

Am einfachsten wäre es, wenn du alle Einträge der TStringlist durchgehst und für jeden Eintrag die Funktion aufrufst.
Achte aber drauf, dass du mit den Rückgabewerten der Funktion auch was anstellst, sonst sind die nämlich weg ;)


Thunfisch - Mi 29.06.11 20:13

Ja mensch cih hab total den Blackout

Wie wäre es mit :



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
 var
        testlist : Tstringlist;
        ShortSpeicher : array[3..,500..];

begin
       testlist := tstringlist.create   ;
        testlist.loadfromfile('vokabeln.txt') ;

For i := 1 to ID begin // Id hab ich vorher mal bestimmt 
   
  StrToVokabelInfo(testlist[i]) ;

ShortSpeicher[1,i] := testlist[i].ID;
Shortspeicher[2,i] := testlist[i].detusch;
Shortspeicher[3,i] := testlist[i].englisch;

end;


Ich bekomme immer, wenn ich StrtoVokabelinfo() aufrufe eine fehlermeldung: [Fehler] Unit1.pas(275): Inkompatible Typen: 'String' und 'TStringList'


Jann1k - Mi 29.06.11 20:25


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
 var
  i:integer;
  testlist : Tstringlist;
  ShortSpeicher : array[0..500of TVokabelInfo;

begin
  testlist := tstringlist.create   ;
  testlist.loadfromfile('vokabeln.txt') ;

  For i := 0 to testlist.count-1  
    //über lines greift man auf die zeilen einer tstringlist zu
    ShortSpeicher[i]:=StrToVokabelInfo(testlist.lines[i]) ; 

  testlist.free();
end;


Das klappt immerhin schonmal, wenn insgesamt weniger als 500 Vokabeln vorhanden sind (besser wäre es die Anzahl der Vokabeln dynamisch auszulesen). ShortSpeicher sollte aber global definiert werden, sonst sind die eingelesenen Daten am Ende der Prozedur auch wieder weg.


Thunfisch - Mi 29.06.11 20:40

Warum denn keine Matrix mehr?


Jann1k - Mi 29.06.11 20:41

Wofür willst du die Matrix haben? Du hast doch schon dein Record TVokabelInfo, dann kommst du mit ShortSpeicher[i].deutsch etc. bequem an die Werte.


Thunfisch - Mi 29.06.11 21:07

Hier habe ich mir eine neue funktion geschrieben aber mittels alt+v eingefügt und jetzt meldet mir delhpi eine Menge komischer Probleme.
Wie muss ich diese procedure oben in die types einfügen?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
procedure TForm1.StrToVokabelInfo(str: stringvar vokabel: TVokabel);
var
  i, j: integer;
  temp1: string;
begin
  vokabel.id '';
  vokabel.Deutsch := '';
  vokabel.Englisch := '';
  i := 1;
  while str[i] <> '#' do begin
   vokabel.id := vokabel.id + str[i];
   i := i + 1;
  end;

  i := i + 1;
  while str[i] <> '#' do begin
   vokabel.Deutsch := vokabel.Deutsch + str[i];
   i := i + 1;
  end;
  for j := i + 1 to length(str) do begin
   vokabel.Englisch := vokabel.Englisch + str[j];
  end;
end;


Jann1k - Mi 29.06.11 21:26

"Eine Menge komischer Probleme" ist eine saubere Fehlerbeschreibung.

Weißt du eigentlich was du da machst? In der ersten zeile fehlt dir ein Zuweisungsoperator und wenn du aus ID nicht jetzt einen String gemacht hast (vorher wars ein integer) klappt deine erste Teilschleife so nicht.

P.S: Die Meldungen der komischen probleme sagen dir eigentlich recht deutlich wo etwas im argen liegt.


Thunfisch - Mi 29.06.11 21:39

sorry für die ungenaue beschreibung. Hier nochmal alle fehlermeldungen, die ich bekomme (Ich denke durch die richtige definierung in type lösen sich die meisten):

[Fehler] Unit1.pas(41): Undefinierter Bezeichner: 'TVokabel' (habe ich definiert)
[Fehler] Unit1.pas(56): Bezeichner redefiniert: 'TVokabel'
[Fehler] Unit1.pas(93): Operator oder Semikolon fehlt (mitten in der zeile bzw befehl)
[Fehler] Unit1.pas(94): Operator oder Semikolon fehlt (mitten in der zeile bzw befehl)
[Fehler] Unit1.pas(104): ',' oder ')' erwartet, aber Bezeichner 'D' gefunden
[Fehler] Unit1.pas(104): Operator oder Semikolon fehlt
[Fehler] Unit1.pas(201): Inkompatible Typen: 'TObject' und 'String'
[Fehler] Unit1.pas(213): Deklaration von 'StrToVokabelInfo' unterscheidet sich von vorheriger Deklaration
[Fehler] Unit1.pas(218): Operator oder Semikolon fehlt

Und noch ca 10 mal operator oder semikolon fehlt

Wie gesagt
Zitat:
Ich denke durch die richtige definierung in type lösen sich die meisten


Also ich brauch nur wissen wie man die prozedur manuell in die type deklaration einträgt. Den Rest bekomme ich selbst hin


Oliver Maas - Mo 04.07.11 17:47

Hi

ich bin vermutlich spät dran, aber du hast ja (nehme ich an) ein Formular der Klasse TForm1,
darunter gibt es dann ja private ... public ... end;
Wenn du die procedure private haben willst, dann schreib unter private


Quelltext
1:
procedure StrToVokabelInfo(str: string; var vokabel: TVokabel);                    


zudem kannst du ja TVokabel vor TForm1 deklarieren.

viele Grüße

Olli