Avatar billede lanstorp Nybegynder
08. august 2002 - 14:36 Der er 48 kommentarer og
2 løsninger

ASCII til array

Har en ASCII fil med tal i tre kolonner adskildt af et mellemrum, eks:
x y z

3432 34234 45
3453 46566 76
6776 45454 45 ... osv.

Hvad er den mest simple måde, at få disse værdier smidt over i et record array som:

pkt[i].x
pkt[i].y
pkt[i].z
Avatar billede borrisholt Novice
08. august 2002 - 14:53 #1
således

pkt[i].x bliver 3432  første gang og
3453 anden gang ?

eller bliver den 34234 anden gang

Jens B
Avatar billede hermandsen Juniormester
08. august 2002 - 14:55 #2
Skal mellemrummene overhovedet være der?
Avatar billede lanstorp Nybegynder
08. august 2002 - 14:56 #3
Den først var rigtig. Er at betragte som tre kolonner x,y,z:
Altså: pkt[i].x bliver 3432 første gang og 3453 anden gang og
pkt[i].z bliver 45 første gang og 76 anden gang
Avatar billede lanstorp Nybegynder
08. august 2002 - 14:59 #4
>>Hermandsen, Ja, Mellemrum adskiller de tre 'kolonner'.
Data er geografiske koordinater: x,y og en højde z adskildt af mellemrum.
En koordinat (pkt) i hver linie i ASCII filen.
Avatar billede borrisholt Novice
08. august 2002 - 15:09 #5
noget alla det her :
type
  TPlysHest = packed record
    x,y,z : Integer;
  end;
  TTokenNum = 1..3;


procedure TForm1.FormCreate(Sender: TObject);
begin
  StringList := TStringList.Create;
  StringList.Add('3432 34234 45');
  StringList.Add('3453 46566 76');
  StringList.Add('6776 45454 45');

end;

procedure TForm1.Button1Click(Sender: TObject);
  function GetToken(var aStr : String; const Delimiter : Char = #32) : Integer;
  var
    i : Integer;
  begin
    i := pos(Delimiter, aStr);
    if i = 0 then
      Result := StrToInt(aStr)
    else
      Result := StrToInt(copy(aStr, 1, i-1));
    Delete(aStr, 1, i);
  end;

var
  PlysHest : TPlysHest;
  i : Integer;
  s : String;
begin
  for i := 0 to StringList.Count -1 do
  begin
    s := StringList[i];
    PlysHest.x := GetToken(s);
    PlysHest.y := GetToken(s);
    PlysHest.z := GetToken(s);
  end;
end;


Jens B
Avatar billede borrisholt Novice
08. august 2002 - 15:11 #6
Dit problem er du burger for få heste i dit programmering ... ALTID : Hvis det ikke virker så tilføj flere heste !

Jens B
Avatar billede hermandsen Juniormester
08. august 2002 - 15:11 #7
Nå, så gik browseren ned, men jeg prøver igen! ;)

type
  3DPoint = record
    x: Integer;
    y: Integer;
    z: Integer;
  end;

  TForm1 = class(TForm)
  ...
  private
    P: array of 3DPoint;

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
  sl: TStringList;
  S: String;
begin
  sl := TStringList.Create;
  sl.LoadFromFile(ExtractFilePath(Application.ExeName) + 'MyFile.txt');
  SetLength(P,  sl.Count);
  for I := 0 to sl.Count -1 do
  begin
    S := sl.Strings[I];
    P[I].x := StrToInt(Copy(S, 0, Pos(' ', S)-1));
    S := Copy(S, Pos(' ')+1, Length(S));
    P[I].y := StrToInt(Copy(S, 0, Pos(' ', S)-1));
    P[I].z := StrToInt(Copy(S, Pos(' ')+1, Length(S)));
  end;
  sl.Free;
end;

Noget i den retning havde jeg da forestillet mig! ;)
Avatar billede hermandsen Juniormester
08. august 2002 - 15:15 #8
Hehe... Kan se at det jeg har lavet faktisk liner borrisholt's eksempel ret godt! ;)

Nå, men mit var egentlig også et svar, så her kommer det... :)
Avatar billede hermandsen Juniormester
08. august 2002 - 15:16 #9
Mener dog at borrisholt skal ha' point for brug af flest heste!!!
Avatar billede lanstorp Nybegynder
08. august 2002 - 15:20 #10
>>hermandsen,
Borrisholt ikke kun bruger flest heste, han burger dem også (se tekst)

Takker begge
Avatar billede zerohero Nybegynder
08. august 2002 - 15:39 #11
Det kan gøre meget lettere... :-))

type
  T3DPoint = record
    x: Single;
    y: Single;
    z: Single;
  end;

function ReadFile(S : String) : array[0..100] of T3DPoint;
var
  F : TextFile;
  Data : Char;
  RData : String;
  i, iCount : Integer;
  P : array[0..100] of T3DPoint;
begin
  if FileExists(S) then
  begin
    i := 0;
    iCount := 0;
    try
      AssignFile(F,S);
      Reset(F);
      while not eOf(F) do
      begin
        Read(F,Data);

        if (Data in [Chr(32)..Chr(255)]) then
        begin
          if Data [Chr(33..Chr(255)] then
          RData := RData+Data
          else
            begin
              Inc(i,1);
              case i of 
                1: P[iCount].X := FloatToStr(RData);
                2: P[iCount].Y := FloatToStr(RData);
                3: begin
                    P[iCount].Z := FloatToStr(RData);
                    i := 0;
                  end;
                end;
              RData := '';
            end;
        end
        else
          Inc(iCount,1);
      end;
      CloseFile(F);
    except
      ShowMessage('Fejl ved indlæsning af filen: '+Dir);
    end;
  end
  else
    ShowMessage('Kan ikke finde filen: '+Dir);

  Result := P;
end;

Jeg har ikke testet den, men noget lign. dette kunne vel sagtens bruges :-))
NB: Du kan selv ændre til Dynamic arrays, hvis dette er en fordel for dig!

Held og Lykke

ZeroHero
Avatar billede zerohero Nybegynder
08. august 2002 - 15:41 #12
Hovsa Dir skal lige erstattes med S!!!!
Avatar billede borrisholt Novice
08. august 2002 - 15:47 #13
zerohero>> Det er vel i højgrad en smagssag om man vil bruge en TStringList eller du vil læse en linje af gangen. Hvis du vil det brude man så ikke bruge en TReader ?

Anyway din ide med et Array bryder jeg mig ikke meget om .... Jeg ville indsætte indsætte mine data i en binært træ, eller i det mindste blot en TList ligende dims ... Den er meget hurtigere at søge i.

Jens B
Avatar billede hermandsen Juniormester
08. august 2002 - 16:05 #14
Oups, jeg ser lige at der forresten også skulle et T foran min 3DPoint-record... Typer må jo ikke stare med tal! ;)

>>zerohero
Hvorfor bruger du egentlig P? Udskift den med Result, så sparer du en 2 linier kode og 201 records af 4 bytes, altså 804 bytes hukommelse!!! ;)
Avatar billede hermandsen Juniormester
08. august 2002 - 16:10 #15
Undskyld at jeg lige spammer lidt...

>>borrisholt
Kan du ikke fortælle mig hvor jeg skal tilføje de sidste heste ved det her problem? http://www.eksperten.dk/spm/242321
Avatar billede martinlind Nybegynder
08. august 2002 - 17:53 #16
zerohero >> at læse det hele ind i en TStringList er også MEGET hurtigere end at læse EN line adgangen, en TStringList er hamrende hurtig til at læse data ind i forhold til en std. TextFile

/Martin
Avatar billede zerohero Nybegynder
08. august 2002 - 20:07 #17
Hmmm... jeg troede egentligt at det var hurtigere på den måde jeg havde skrevet det, men det var nok ikke besværet værd alligevel...

BorrisHolt>> Kan du ikke lige lave en simpel eksempel med TReader???
Avatar billede erniez13 Nybegynder
12. august 2002 - 18:27 #18
Lav det i optimized assembly!.. Ville nok få en 30000% hastighedsoptimering ;o)
Hvis du har interesse kan jeg hive koden frem til dig ;)
Avatar billede hermandsen Juniormester
12. august 2002 - 19:04 #19
>>erniez13
Jeg vil gerne se det!
hermandsen@softhome.net (hvis der er meget)
Avatar billede lanstorp Nybegynder
12. august 2002 - 23:12 #20
>>erniez13
30000% hastighedsoptimering = hvorfor få resultater i dag når man kunne have fået det i går. Den kode vil jeg også gerne se.
30000procenthvorvildt@lanstorp.com
Avatar billede erniez13 Nybegynder
13. august 2002 - 00:04 #21
Hehe, såså, 30000% er nok lidt overdrevet (Det er ikke sådan så den kan skrue tiden tilbage eller noget - Men det kunne være fedt! :P) , men ihvertfald en fordobling af hastigheden kan man godt forvente... Den kode jeg har egner sig ikke helt til spørgsmålet her, så jeg skal lige omskrive den en lille smule når jeg får tid, jeg skal nok poste den her i løbet af ugen til jer! ;)
Avatar billede hermandsen Juniormester
13. august 2002 - 07:49 #22
Cool cool... :)
(beklager spam)
Avatar billede zerohero Nybegynder
13. august 2002 - 10:36 #23
erniez13>> Kan du ikke vise koden her på Eksperten! Jeg tror der er flere der er interesseret i at se koden! (eksempelvis mig) :-))...
Avatar billede borrisholt Novice
13. august 2002 - 10:38 #24
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

type
  THesteRecord = record
    S : String;
  end;

  TMyWriter = class(TWriter)
    Procedure WriteHesteRecord(Const HesteRecord : THesteRecord);
  end;

  TMyReader = class(TReader)
    procedure ReadHesteRecord(var HesteRecord : THesteRecord);
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  FileStream : TFileStream;
  i : Integer;
  HesteRecord : THesteRecord;
  Writer : TMyWriter;
begin
  FileStream := TFileStream.Create('C:\Hest.txt', fmCreate);
  Writer := TMyWriter.Create(FileStream, $FF);
  Writer.WriteListBegin;

  for i := 0 to 10 do
  begin
    HesteRecord.S := IntToStr(i);
    Writer.WriteHesteRecord(HesteRecord);
  end;
  Writer.WriteListEnd;
  Writer.Destroy;
  FreeandNil(FileStream);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  FileStream : TFileStream;
  HesteRecord : THesteRecord;
  Reader : TMyReader;
begin
  FileStream := TFileStream.Create('C:\Hest.txt', fmOpenRead or fmShareDenyWrite);
  Reader := TMyReader.Create(FileStream, $FF);
  Reader.ReadListBegin;

  while not Reader.EndOfList do
  begin
    Reader.ReadHesteRecord(HesteRecord);
    Memo1.Lines.Add(HesteRecord.S);
  end;

  Reader.ReadListEnd;
  Reader.Free;
  FileStream.Free;
end;

{ TMyWriter }

procedure TMyWriter.WriteHesteRecord(const HesteRecord: THesteRecord);
begin
  WriteString(HesteRecord.S)
end;

{ TMyReader }

procedure TMyReader.ReadHesteRecord(var HesteRecord: THesteRecord);
begin
  HesteRecord.S := ReadString;
end;


end.

Jens B
Avatar billede zerohero Nybegynder
13. august 2002 - 12:34 #25
JensB>> under proceduren Button1Click i sidst linje "FreeandNil(FileStream);" - Hvad betyder det???
Avatar billede zerohero Nybegynder
13. august 2002 - 12:35 #26
Skal den ikke bare frigøres som i proceduren Button2Click "FileStream.Free;" ???
Avatar billede borrisholt Novice
13. august 2002 - 12:38 #27
Hvis du bare kalder .Free på et object så beholder Object Referencen sin værdi. Selv om Objectet er frigivet. Det kan give problemer hvis du længere nede i din kode bruger If assigned(....). Derfor har Borland i D5 indført en Procedure der hedder FreeAndNil. Den Free Objecter OG sætter Obj Referencen til Nil.

Altså :

var
  Hest : TObject;
begin
  Hest := TObject.Create;
  Hest.Free;
  If Assigned(Hest) then
    ShowMessage('');

  Hest := TObject.Create;
  FreeAndNil(Hest);
  If Assigned(Hest) then
    ShowMessage('');
end;

Jens B
Avatar billede borrisholt Novice
13. august 2002 - 12:47 #28
Description

Use FreeAndNil to ensure that a variable is nil after you free the object it references. Pass any variable that represents an object as the Obj parameter.

Warning:    Do not pass a value for Obj if it is not an instance of TObject or one of its descendants.
Avatar billede zerohero Nybegynder
13. august 2002 - 12:47 #29
Aha... men jeg sidder med D4 - hvordan kan jeg frigøre den uden at få eventuelle problemer senere?
Avatar billede zerohero Nybegynder
13. august 2002 - 12:52 #30
Ellers mange tak for den fine eksempel... Den virker trods alt på min D4 (indtil videre) :-))
Avatar billede borrisholt Novice
13. august 2002 - 12:59 #31
Enten implm. den selv

procedure FreeAndNil(var Obj);
var
  P: TObject;
begin
  P := TObject(Obj);
  TObject(Obj) := nil;  // clear the reference before destroying the object
  P.Free;
end;


eller brug .free

Jens b
Avatar billede zerohero Nybegynder
13. august 2002 - 13:19 #32
Mange tak...
Avatar billede borrisholt Novice
13. august 2002 - 14:25 #33
Jeg har et lidt stører og mere brugbart eksempel på Hvordan man bruger TReader og Twriter til at lave sit eget filformat... Hvis du vil have det så drop mig en mail og bed om min THorseFile

Jens B
Avatar billede martinlind Nybegynder
13. august 2002 - 14:32 #34
Er det ikke lidt overkill og bruge TWriter/TReader til den slags småting det er da hurtigere bare at lave en

File of TMyRec;

og så høvle det ned, eller en TStream

/Martin
Avatar billede borrisholt Novice
13. august 2002 - 14:36 #35
Type
  TMyRec = record
    S : String;
    W : WideString;
  end;

Den kan du ikke bruge i en File og TMyRec. Der kan du kun have ordinære type ....

Derfor TReader og TWriter !

Jens B
Avatar billede martinlind Nybegynder
13. august 2002 - 14:41 #36
Eller en TStream eller TStringList eller

  Type

  TMyRec = record
    S : String[100];
  end;

/Martin
Avatar billede hermandsen Juniormester
13. august 2002 - 14:42 #37
Yeps!

Dog kan problemet løses:

procedure WriteString(var F: File; const S: String);
var
  Size: Word;
  P: PChar;
begin
  Size := Length(S);
  GetMem(P, Size+1);
  StrCopy(P, PChar(S));
  BlockWrite(F, Size, 2);
  BlockWrite(F, P^, Size);
  FreeMem(P);
end;

Jeg havde store problem en gang jeg skulle gemme et array of record med en masse strings... :)
Avatar billede martinlind Nybegynder
13. august 2002 - 14:43 #38
Hvis man endelig VIL bruge TReader/TWriter så er det smarteste at lave sin Record om til en Class der arver fra TPersistent og så lave sine Record-felter om til Published propertis så er alt koden nemlig lavet for dig, så kan du bare høvle det ned med en TFileStream.WriteComponent();

/Martin
Avatar billede borrisholt Novice
13. august 2002 - 14:45 #39
Jo jo ... Der er veje uden om ....

1)
  Du kommer ALDRIG til at kunne streame en klasse ned i  en Fil med file of ....
2)
  Du Gemmer en masse tom plads.
3)
  Det froholder sig med TReader og TWriter kontra File of som der gør mellem procedural og Objectorienteret programmering !

:-)

Jens B
Avatar billede hermandsen Juniormester
13. august 2002 - 14:46 #40
Når der så skal læses fra min løsning:

function ReadString(var F: File): String;
var
  Count: Word;
  Buf: array [1..300] of Char;
begin
  BlockRead(F, Count, 2);
  BlockRead(F, Buf, Count);
  Result := Copy(Buf, 0, Count);
end;

>>martinlind
Får man så ikke en masse med i den fil man gemmer som egentlig ikke behøves?
Avatar billede martinlind Nybegynder
13. august 2002 - 14:47 #41
Mit Sidste foreslag har den store fordel at du ikke behøver ændre i din Save/Load rutine du add'er bare nogle ny property så bliver de automatisk gemt/hentet ( jeg lavede på et tidspunkt et fuldstændigt selv tilpassende adr. kartotek, nye felt addede man bare til DataClass'en så tilpassede resten af prg. sig, grid'er osv. )
Avatar billede hermandsen Juniormester
13. august 2002 - 14:48 #42
>>martinlind
Hvor meget fyldte den færdige fil? Er bare nysgerrig... :)
Avatar billede martinlind Nybegynder
13. august 2002 - 14:49 #43
Hermandsen >> Det er faktisk ikke så slemt, jeg lavede et eks. med 100000 adr. kort de fyldte < 100kb så det kan man sagtens leve med til hjemme brug
Avatar billede martinlind Nybegynder
13. august 2002 - 14:49 #44
som en alm Delphi EXE
Avatar billede borrisholt Novice
13. august 2002 - 14:51 #45
Jeg sunes den med de published properties ikke er for god ... Dels kan du kun Gemme published data, og dels synes jeg man bliver meget bunder op af et meget simpelt filformat ....

Jeg brug nedarvninger af hhv. TStream og TWriter, således de kan læse og skrive en hel record af gangen ....

Jens B
Avatar billede martinlind Nybegynder
13. august 2002 - 14:55 #46
Du er IKKE mere bundet en Delphi's comp. er bundet, og det er jo ikke ret meget *G*, da du kan impl. de avancerede typer som du normalt gør hvis det var en comp. du lavede, men du får resten foræret
Avatar billede hermandsen Juniormester
13. august 2002 - 14:59 #47
Hmmm... Jeg har en klasse der ser således ud:

TFile = class(TObject)
  private
    vName: String;
    vSourceDir: String;
    vDestDir: String;
    vSize: Integer;
    vDownloaded: Integer;
    vStatus: TFileStatus; {TFileStatus = (fsDownloading, fsPaused, fsQueued, fsSearching, fsFileNotFound, fsNone)}
    vID: Integer;
  ...

Hvor jeg skal ha' gemt vName, vSourceDir, vDestDir, vSize og vDownloaded (de er erklæret som properties)...

Jeg har så lige prøvet at gemme ca. 300 TFile's (på min måde) i en fil... Den fylder omkring 20kb, så hvordan du har båret dig ad med at få 100000 adr. kort ned under 100kb er jeg helt sikkert meget interesseret i at vide!!! :)
Avatar billede borrisholt Novice
13. august 2002 - 15:28 #48
Jeg har lige tested min
10000 records + Headder.

Fylder : 135 kb.
Tidsforbrug : 0,034 Seconds

Jens B
Avatar billede hermandsen Juniormester
13. august 2002 - 15:39 #49
7002 TFile's gemt på min måde...
0,528 sekunder (brugte bare GetTickCount, så regn ikke med præcition)
740 kb

Hmmm... Jeg tror da vist at jeg skal til at bruge din metode, Jens! :)
Vil da gerne lige forsvare mig selv og sige at mange af mine strenge er lidt halv-lange... :)
Avatar billede martinlind Nybegynder
13. august 2002 - 16:59 #50
Lav din class om til at arve fra TPersistent og flyt dinne property's ned til published, så kan du gemme med WriteComponent / WriteComponentRes, jeg mener jeg brugte Res udgaven for at få det til at fylde mindre
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester