Avatar billede dudepres Nybegynder
04. marts 2004 - 14:04 Der er 8 kommentarer og
4 løsninger

Er det en stringlist jeg skal bruge?

Hej,

jeg henter nogle linier ind fra et tekstdokument (notepad) som jeg skal havde delt lidt op på.

En linie er formet efter: "ID","Varernavn","antal"

Jeg vil så splitte det ud i et slags stinglist eller array som:
Myarray: [1..10] of string [1|2|3]

ved ikke lige hvilken slags list der kan det, men ideen er at kunne kalde MyArray[1|1] som så giver "ID" og MyArray[1|2] som giver "Varernavn" osv.

Lidt forvirrende I know.
Avatar billede dudepres Nybegynder
04. marts 2004 - 14:35 #1
Noone?
Avatar billede screwdriver Nybegynder
04. marts 2004 - 15:00 #2
Det kan du med en TStringGrid

f.eks.

  StringGrid1.Cells [ 0, 1 ] := Varenavn ;
Avatar billede dudepres Nybegynder
04. marts 2004 - 16:24 #3
Kræver det et synligt stringgrid?
Avatar billede nlf Nybegynder
04. marts 2004 - 18:30 #4
Hvis ikke du vil have det i et stringgrid, så lad være med at bruge stringgrid, det tager for meget hukommelse, brug hellere arrays.
Her bliver der lavet et dynamisk array, dvs. et array der kan fyldes op til du brækker dig. Dvs. at fx MyArray[0][0] er ID og fx MyArray[0][1] er Varenavn.

var
  MyArray : array of array [0..1] of String;

Når du skal tilføje noget kan det gøres således, ved først at øge arrayet, da det er dynamisk, og så bagefter sætte S, som er teksten, ind på enten ID eller Varenavns plads (du må selv bestemme om det 0 eller 1 ID skal stå på, det gør ingen forskel):

procedure AddString(Valg : Integer, S : String);
begin
  SetLength(MyArray, High(MyArray)+1);
  MyArray[High(MyArray)][Valg] := S;
end;
Avatar billede screwdriver Nybegynder
04. marts 2004 - 18:45 #5
Hvis du bruger et StringGrid, behøver du ikke at vise det på formen. Du kan bare sætte Visible := False,

eller lave et runtime ... f.eks.

procedure TForm1.Button5Click(Sender: TObject);
Var
  MyStringList : TStringGrid ;
begin
  MyStringList := TStringGrid.Create ( Form1 );
  MyStringList.Cells [ 1, 1 ] := 'test' ;
  Edit2.Text := MyStringList.Cells [ 1, 1 ] ;
  MyStringList.Free ;
end;

Men det smarteste, hvis du ikke vil have det vist på skærmen, vil klart være et array, som nlf nævner
Avatar billede nop Nybegynder
05. marts 2004 - 14:06 #6
Her er en lidt bedre måde at bruge et variabelt array på

type
  myRec = record
    id:  integer;
    vareTxt: string;
  end;

var
  myArray: array of myRec;

begin
  setLength(myArray,1000);
  with myArray[34] do begin
    id:=1234;
    vareTxt:='Det her er bare et eksempel.';
  end;
end.
Avatar billede nop Nybegynder
05. marts 2004 - 14:09 #7
osse fx:

var
  count: integer;


  procedure add(i: integer; t: string;
  begin
    inc(count);
    setLength(myArray,count);
    with myArray[count] do begin
      id:=i;
      vareTxt:=t;
    end;
  end;

begin
  //det her er pseudokode
  count:=0;
  find første vare
  while not vare.eof do begin
      add(varenr,vareTxt);
      next vare;
  end;
  msg('Dinne varer er nu i ram array.');
end.
Avatar billede nop Nybegynder
05. marts 2004 - 14:11 #8
hov: with myArray[count-1] do begin  //-1 er vigtigt
--nop
Avatar billede hrc Mester
05. marts 2004 - 15:54 #9
Hvorfor ikke lave det lidt objektorienteret???

uses
  SysUtils, Classes, Contnrs;

type
  TVare = class
  private
    fID : string;
    fNavn : string;
    fAntal : integer;
  public
    constructor Create(aSt : string);
    property ID : string read fID;
    property Navn : string read fNavn;
    property Antal : integer read fAntal write fAntal;
  end;

  TVareListe = class
  private
    fList : TObjectList;
    function GetVare(aIndex: integer): TVare;
  public
    constructor Create(const aFileName : string);
    destructor Destroy; override;
    property Items[aIndex : integer] : TVare read GetVare; default;
    function Count : integer;
  end;

implementation

{ TVare }

const
  StringDelimiter : char = '"';
  FieldDelimiter : char = ',';

constructor TVare.Create(aSt: string);
var
  i : integer;
  bField : boolean;
  bString : boolean;
  StringList : TStringList;

  function RemoveDelimiters(aSt : string) : string;
  begin
    result := copy(aSt,2,length(aSt)-2);
  end;

begin
  inherited Create;

  StringList := TStringList.Create; // Parse strengen
  try
    repeat
      i := 1; bString := false; bField := false;
      while (i < length(aSt)) and not bField do begin
        if aSt[i] = StringDelimiter then
          bString := not bString;

        if not bString then
          bField := aSt[i] = FieldDelimiter;

        if bField then begin
          StringList.Add(copy(aSt,1,i-1));
          delete(aSt,1,i);
        end; // if
        inc(i);
      end; // while
    until i = length(aSt);
    StringList.Add(aSt);

    fId := RemoveDelimiters(StringList[0]);
    fNavn := RemoveDelimiters(StringList[1]);
    fAntal := StrToInt(StringList[2]);
  finally
    StringList.Free;
  end; // try
end;

{ TVareListe }

function TVareListe.Count: integer;
begin
  result := fList.Count;
end;

constructor TVareListe.Create(const aFileName: string);
var
  fp : textfile;
  st : string;
begin
  inherited Create;
  fList := TObjectList.Create;

  assignfile(fp,aFileName);
  reset(fp);
  try
    while not eof(fp) do begin
      readln(fp,st);
      fList.Add(TVare.Create(st));
    end; // while
  finally
    closefile(fp);
  end; // try
end;

destructor TVareListe.Destroy;
begin
  try
    fList.Free;
  finally
    inherited;
  end; // try
end;

function TVareListe.GetVare(aIndex: integer): TVare;
begin
  result := TVare(fList.Items[aIndex]);
end;


I dit program kan du eksempelvis lave følgende:

var
  VareList : TVareListe;
  i : integer;
begin
  VareList := TVareListe.Create('c:\varer.txt');
  try
    for i := 0 to VareList.Count - 1 do
      lbVarer.Items.Add(VareList[i].Navn); // Læser vare i's navne-property
  finally
    VareList.Free;
  end;
end;

Med fare for at jokke i spinaten igen, så er det den rette måde at gøre tingene på. TVare ved hvordan constructorens aSt skal håndteres og TVareListe åbner en fil og opretter så mange TVare objekter som der er linier i filen.

Du er blevet rådet til at arbejde med en TStringGrid - hvad med en TListView imed ViewStyle sat til vsReport. Det er bagefter også let eksempelvis at sortere listen efter de kolonner man klikker på. Jeg foretrækker klart TListView fremfor TStringGrid, en komponent som er blevet lavet under en mental blackout.

Bemærk, at det forudsættes at txt-filen er korrekt. Der er ingen fejlhåndtering.
Avatar billede dudepres Nybegynder
09. marts 2004 - 10:21 #10
Jeg takker alle for de fine (og  meget detaljeret) svar. Beklager at der ikke er flere point at give.
Avatar billede hrc Mester
10. marts 2004 - 01:07 #11
Tak for de mange points ;-) Min parse-funktion i TVare constructoren kan vist (har ikke afprøvet det) erstattes med denne:

constructor TVare.Create(aSt: string);
var
  i : integer;
  bField : boolean;
  bString : boolean;
  StringList : TStringList;

begin
  inherited Create;

  StringList := TStringList.Create; // Parse strengen
  try
    StringList.CommaText := aSt;

    fId := StringList[0];
    fNavn := StringList[1];
    fAntal := StringList[2];
  finally
    StringList.Free;
  end; // try
end;

Desuden så laver jeg en stor fejl i "fList := TObjectList.Create;". Den korrekte linie er: "fList := TObjectList.Create(true);" idet objekterne i listen, først nu, frigives. Beklager.
Avatar billede hrc Mester
10. marts 2004 - 12:06 #12
Lige endnu en rettelse. Der er ingen forskel om man opretter en TObjectList med eller uden Create(true). Hjælpeteksten påstår godtnok noget andet, men uanset hvad man gør, så frigiver listen tilsyneladende objekterne uden problemer.

Mht. StringList.CommaText, så kan jeg bekræfte at det virker. En lille ulempe er, at man ikke kan se om tal er tal eller en række tegn fordi anførselstegnene fjernes. Eksempelvis er kan man ikke se om 20041211 er et stort tal eller en streng der angiver en dato. Det havde været synligere med "20041211".
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