how to get two different file with this procedure

2019-09-17 18:58发布

问题:

i want to get value from two file .txt, one file contain different dimension matrix with other

i have try this code:

  procedure TfrmJST.ParseDelimited(const S1: TStrings; const Value: String; const Delimiter: String);
    var
      dx,cx: integer;
      ns,ms: String;
      txt: string;
      delta,teta: integer;

   procedure TfrmJST.ParseDelimited(const S1: TStrings; const Value: String; const Delimiter: String);
var
  dx,cx: integer;
  ns,ms: String;
  txt: string;
  delta,teta: integer;

    begin
     Col := 1;
     Delta := Length(Delimiter);
     Txt := Value+Delimiter;;
     begin
      while Length(Txt) > 1 do
      begin
        Dx := Pos(Delimiter, Txt);
        Ns := Trim(Copy(Txt, 1, Dx-1));
    //    S1.Add('#'+Ns+'*');             //only needed for testing
        if Ns <> '' then
        begin
          Matrix[Row,Col] := StrToFloat(Ns);    //for first matrix
          Inc(Col);
        end;
        Txt := Copy(Txt, Dx+Delta, MaxInt);
      end;
     end;



     Col := 1;
     teta := Length(delimiter);
     txt := value+delimiter;
     begin
      while Length(txt) > 1 do
      begin
        cx := Pos(delimiter, txt);
        ms := Copy(txt, 1, cx-1);
        if ms <> '' then
          begin
          ref[Row,Col] := StrToFloat(ms);    ///for 2nd matrix

          Inc(Col);
          end;
          txt := Copy(txt, cx+teta, MaxInt);
      end;
     end;
    end;

and this is initialize of matrix:

private
    { Private declarations }
    Row, Col: integer;
    Matrix: array[1..140,1..141] of double;
     Ref: array[1..2,1..140] of double ;

this is the implementation:

begin
  Temp := TStringList.Create;
  MemoSL:= TStringList.Create ;
  Temp.LoadFromFile('trainer.txt');
  Row := 1;
  for I := 0 to Temp.Count-1 do
  begin
    ParseDelimited(MemoSL, Trim(Temp.Strings[I]), ' ');
    Inc(Row); //stackoverflow error in this line
  end;
  Temp.Free;

 //parsing second matrix
  TempList := TStringList.Create;
  Templist.LoadFromFile('refbaru.txt');
  row := 1;
  for J := 0 to Templist.Count-1 do
  begin
 T := Templist[J];
 ParseDelimited(Memo1.Lines, T, ' ');
  Inc(row);
  end;
  Templist.Free;

i tried that code but give me error, the error was stackoverflow error in line 'inc(row)' that process first matrix. and while i gave comment out at the second function that process 2nd matrix, Temp[i] only returns 2 rows of matrix[140x141]. does it mean the code can't process two different file? and why it only return two rows of the matrix? anyone can help me?

回答1:

while Length(Txt) > 1 do
begin
  Dx := Pos(Delimiter, Txt);
  Ns := Trim(Copy(Txt, 1, Dx-1));
  //    S1.Add('#'+Ns+'*');             //only needed for testing
  if Ns <> '' then
  begin
    Matrix[Row,Col] := StrToFloat(Ns);    //for first matrix
    Inc(Col);
  end;
  Txt := Copy(Txt, Dx+Delta, MaxInt);
end;

Looking at this piece of code I see the posibility of an endless loop: what happens if there is no Delimiter found? It will keep running and forever increase your 'col' value. Make sure to have a condition to stop your while loop if no delimeter is found.



回答2:

It is pointless to look for a specific stack overflow error when many ordinary errors already exist.

If your code is clean programmed and it is still stack overflow, then of course, is time to look deeper into the code.
But first ! As long as you can see obvious errors, you should remove them.

  • 1.) "Row" used in the same procedure on a 140 dimension array and on a only 2 dimension array. How can that work ?

Matrix: array[1..140,1..141] of double;
Ref: array[1..2,1..140] of double ;
File 'trainer.txt' 140 Lines
File 'refbaru.txt' 2 Lines.

for I := 0 to Temp.Count-1 do // 140 lines
// ParseDelimited() will only run properly if Row < 3 
// remember -> Ref: array[1..2,1..140])
// if Row > 2 , with Ref[Row,Col] := , 137 times data is overwritten.

   procedure ParseDelimited(MemoSL, Trim(Temp.Strings[I]), ' ');
      ....
      Matrix[Row,Col] := StrToFloat(Ns);
      ....
      Ref[Row,Col] := StrToFloat(ms); 
      ....
   end;
Inc(Row);
end;
  • 2.) If you run the second loop with refbaru.txt and the two arrays are present together in the procedure ParseDelimited(), then you overwrite 2 values of array Matrix

recommendation

  • make sure: Loop through trainer.txt, writes values only to the Matrix array.
  • make sure: Loop through refbaru.txt, writes values only to the Ref array.

Your code could look something like:

[...]
filetoload: String;
[...]
procedure TfrmJST.ParseDelimited(S1: TStrings; Value: String; const Delimiter: String);
var
 f:double;
[...]
     Col := 1;
     txt := Value+Delimiter;
[...]
if filetoload='trainer.txt' then begin
     Delta := Length(Delimiter);
      while Length(txt) > 1 do
      begin
        Dx := Pos(Delimiter, txt);
        Ns := Trim(Copy(txt, 1, Dx-1));
        if Ns <> '' then
        begin
          if TryStrToFloat(Ns,f) then Matrix[Row,Col]:=f;
          Inc(Col);
          if Col > MatrixColMax then break;
          txt := Copy(txt, Dx+Delta, MaxInt);        
        end else txt:='';
      end;
end;

if filetoload='refbaru.txt' then begin
     teta := Length(delimiter);
      while Length(txt) > 1 do
      begin
        cx := Pos(delimiter, txt);
        ms := Copy(txt, 1, cx-1);
        if ms <> '' then
          begin
          if TryStrToFloat(ms,f) then Ref[Row,Col]:=f;
          Inc(Col);
          if Col > RefColMax then break;
          txt := Copy(txt, cx+teta, MaxInt);
          end else txt:='';
      end;
end;

begin
[...]

filetoload:='trainer.txt';
Temp := TStringList.Create;
Temp.LoadFromFile(filetoload);
if Temp.Count > MatrixRowMax then LinesToLoad:=MatrixRowMax-1 else
                                  LinesToLoad:=Temp.Count-1;
for I := 0 to LinesToLoad do
   [...]
   ParseDelimited(MemoSL, Trim(Temp.Strings[I]), ' ');
   [...]
end;

filetoload:='refbaru.txt';
TempList := TStringList.Create;
TempList.LoadFromFile(filetoload);
if TempList.Count > RefRowMax then LinesToLoad:=RefRowMax-1 else 
                                   LinesToLoad:=TempList.Count-1;
for J := 0 to LinesToLoad do
   [...]
   ParseDelimited(Memo1.Lines, T, ' ');
   [...]
end;
end;

You should also compare the linesize of the file with the size of the arrays

RefRowMax: integer;
RefColMax: integer;
MatrixRowMax: integer;
MatrixColMax: integer;
LinesToLoad: integer;

....

RefRowMax:=2;
RefColMax:=140;
MatrixRowMax:=140;
MatrixColMax:=141;
....

procedure ParseDelimited()

if filetoload='trainer.txt' then begin
 [...]
 Inc(Col)
 if Col > MatrixColMax then break;

end;

if filetoload='refbaru.txt' then begin
 [...]
 Inc(Col)
 if Col > RefColMax then break;

end;

You should also look for a valid value of Ns , StrToFloat(Ns) before you write to the arrays in ParseDelimited()

  • function TryStrToFloat(const S: string; out Value: Double): Boolean;
    or
  • Val();

  var
  f:double;
  ....
  begin
  ....
  if TryStrToFloat(Ns,f) then Matrix[Row,Col]:=f;
  ....

The OP overwritting many of used data.
And when he has enough data overwritten, he gets a stack overflow error.