Recent

Author Topic: Eliminating empty strings in TStringList when reading from text file.  (Read 22042 times)

avk

  • Hero Member
  • *****
  • Posts: 771
Re: Eliminating empty strings in TStringList when reading from text file.
« Reply #45 on: March 14, 2020, 02:03:29 pm »
Well following is quite old way, but the most PASCALISTIC I think.  :D
Good point.

Well, I overcame Saturday laziness and made a simple test program for the proposed methods (maybe wrong?).
Code: Pascal  [Select][+][-]
  1. program test_del_empty;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$modeswitch nestedprocvars}
  5.  
  6. uses
  7.   Classes, SysUtils, DateUtils, StrUtils, LGUtils, LGStrHelpers;
  8.  
  9. type
  10.   TRemoveProc = procedure(aList: TStringList);
  11.  
  12. var
  13.   CurrProc: string = '';
  14.  
  15. procedure RemoveEmptyLinesMax(aList: TStringList);
  16. var
  17.   I: Integer = 0;
  18. begin
  19.   CurrProc := {$I %currentroutine%};
  20.   while I < aList.Count do
  21.     if aList[I] = '' then
  22.       aList.Delete(I)
  23.     else
  24.       Inc(I);
  25. end;
  26.  
  27. procedure RemovEmptyLinesThaddy(aList: TStringList);
  28. var
  29.   a: array of string;
  30. begin
  31.   CurrProc := {$I %currentroutine%};
  32.   a := aList.Text.Split(LineEnding, TStringSplitOptions.ExcludeEmpty);
  33.   aList.Clear;
  34.   aList.AddStrings(a);
  35. end;
  36.  
  37. procedure RemoveEmptyLinesWinny(aList: TStringList);
  38. var
  39.   s: string;
  40.   p: integer = 1;
  41. begin
  42.   CurrProc := {$I %currentroutine%};
  43.   s := aList.Text;
  44.   repeat
  45.     p := posEX(LineEnding + LineEnding, s, p);
  46.     if p > 0 then
  47.       delete(s, p, length(lineEnding));
  48.     until p = 0;
  49.   aList.Text := s;
  50. end;
  51.  
  52. procedure RemoveEmptyLinesAvk(aList: TStringList);
  53. var
  54.   sb: specialize TGAutoRef<TStringBuilder>;
  55.   function NonEmpty(constref s : string): Boolean;begin Result := s <> '' end;
  56.   procedure Add(constref s: string); begin with sb.Instance do begin
  57.     Append(s); Append(LineEnding) end end;
  58. begin
  59.   CurrProc := {$I %currentroutine%};
  60.   aList.GetEnumerable.Select(@NonEmpty).ForEach(@Add);
  61.   aList.Text := sb.Instance.ToString;
  62. end;
  63.  
  64. procedure RemoveEmptyLinesJamie(aList: TStringList);
  65.   procedure DelEmptyLines(var S: TMemorystream);
  66.   var
  67.     R, W, ST: Pchar;
  68.     CC, LEC: Integer;
  69.     L: char;
  70.   begin
  71.     if (S = nil) or (S.Size = 0) then exit;
  72.     R := PChar(S.Memory);
  73.     W := R;
  74.     ST := W;
  75.     while R^ <> #0 do
  76.       begin
  77.         CC := 0; //Char Count;
  78.         while not (R^ in [#13,#10,#0]) do //Move line content if any
  79.           begin
  80.             W^ := R^;
  81.             Inc(R); Inc(W);
  82.             Inc(CC);  //Char count
  83.           end;
  84.         if CC <> 0 then
  85.           begin
  86.             LEC := 0;  //Line Ending Count
  87.             L := #0;   //Last char in line ending.
  88.             while (R^ in [#13,#10])and(L <> R^)And(LEC<2) Do //Move the Line Ending if Valid content.
  89.               begin
  90.                 L := R^; //Update the last Line ending type incase we have single types.
  91.                 Inc(LEC);
  92.                 W^ := R^;
  93.                 Inc(R);
  94.                 Inc(W);
  95.               end;
  96.           end
  97.         else
  98.           while (R^ in [#13,#10]) Do Inc(R); // Skip over blanks.
  99.       end;
  100.     W^ := #0; // Terminate the end;..
  101.   end;
  102. var
  103.   S:TMemoryStream;
  104. begin
  105.   CurrProc := {$I %currentroutine%};
  106.   S := TMemoryStream.Create;
  107.   aList.SaveToStream(s);
  108.   DelEmptyLines(S);  // The real work horse;
  109.   aList.Text := string(S.Memory);
  110.   S.Free;
  111. end;
  112.  
  113. function NonEmptyCount(aList: TStringList): Integer;
  114. var
  115.   I: Integer;
  116. begin
  117.   Result := 0;
  118.   for I := 0 to Pred(aList.Count) do
  119.     Inc(Result, Ord(aList[I] <> ''));
  120. end;
  121.  
  122. function HasEmptyLines(aList: TStringList): Boolean;
  123. var
  124.   I: Integer;
  125. begin
  126.   for I := 0 to Pred(aList.Count) do
  127.     if aList[I] = '' then
  128.       exit(True);
  129.   Result := False;
  130. end;
  131.  
  132. const
  133.   TestSize = 200000;
  134.   LineSize = 16;
  135.  
  136. function CreateStringList: TStringList;
  137.   function RandomString: string;
  138.   var
  139.     I: Integer;
  140.     p: PChar;
  141.   const
  142.     AlphabetLen = 64;
  143.     Alphabet: PChar = '1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_ ';
  144.   begin
  145.     SetLength(Result, LineSize);
  146.     p := PChar(Result);
  147.     for I := 0 to Pred(LineSize) do
  148.       p[I] := Alphabet[Random(AlphabetLen)];
  149.   end;
  150. var
  151.   I: Integer;
  152. begin
  153.   RandSeed := 1001007;
  154.   Result := TStringList.Create;
  155.   Result.Capacity := TestSize;
  156.   for I := 1 to TestSize do
  157.     if Random(5) <> 0 then
  158.       Result.Add(RandomString)
  159.     else
  160.       Result.Add('');
  161. end;
  162.  
  163. var
  164.   Proc: TRemoveProc = nil;
  165.   Start: TTime;
  166.   Elapsed, TestCount: Integer;
  167.   TestList: TStringList;
  168.  
  169. const Procs: array of TRemoveProc = (
  170.   @RemoveEmptyLinesMax, @RemovEmptyLinesThaddy, @RemoveEmptyLinesWinny, @RemoveEmptyLinesAvk,
  171.   @RemoveEmptyLinesJamie);
  172.  
  173. begin
  174.   for Proc in Procs do
  175.     begin
  176.       TestList := CreateStringList;
  177.       TestCount := NonEmptyCount(TestList);
  178.       Start := Time;
  179.       Proc(TestList);
  180.       Elapsed := MillisecondsBetween(Time, Start);
  181.       if HasEmptyLines(TestList) or (TestList.Count <> TestCount) then
  182.         Writeln(CurrProc, #9'elapsed time(ms): ', Elapsed, ' (failure)')
  183.       else
  184.         Writeln(CurrProc, #9'elapsed time(ms): ', Elapsed);
  185.       TestList.Free;
  186.     end;
  187. end.
  188.  

And here are the results:
Code: Text  [Select][+][-]
  1. RemoveEmptyLinesMax     elapsed time(ms): 3721
  2. RemovEmptyLinesThaddy   elapsed time(ms): 50 (failure)
  3. RemoveEmptyLinesWinny   elapsed time(ms): 3049
  4. RemoveEmptyLinesAvk     elapsed time(ms): 41
  5. RemoveEmptyLinesJamie   elapsed time(ms): 55 (failure)
  6.  

Thaddy

  • Hero Member
  • *****
  • Posts: 16659
  • Kallstadt seems a good place to evict Trump to.
Re: Eliminating empty strings in TStringList when reading from text file.
« Reply #46 on: March 14, 2020, 02:11:39 pm »
@avk: my solution needs procedure RemovEmptyLinesThaddy(const aList: TStringList);? I tested my example and it should work as a procedure as well.
Either const or var.
« Last Edit: March 14, 2020, 02:13:14 pm by Thaddy »
But I am sure they don't want the Trumps back...

avk

  • Hero Member
  • *****
  • Posts: 771
Re: Eliminating empty strings in TStringList when reading from text file.
« Reply #47 on: March 14, 2020, 02:20:52 pm »
I replaced the signature of all procedures with
Code: Pascal  [Select][+][-]
  1.   procedure(const aList: TStringList)
  2.  
but the result has not changed, try it yourself.

MaxCuriosus

  • Full Member
  • ***
  • Posts: 136
Re: Eliminating empty strings in TStringList when reading from text file.
« Reply #48 on: March 14, 2020, 02:43:24 pm »
egsuh #44,
you are right, absent a specialized StringList method that's the easiest to implement and the first I had thought, along with many others I'm sure. To stay exact to my initial demand, in your code trim(s) should be replaced with just s.
« Last Edit: March 14, 2020, 02:45:17 pm by MaxCuriosus »

wp

  • Hero Member
  • *****
  • Posts: 12698
Re: Eliminating empty strings in TStringList when reading from text file.
« Reply #49 on: March 14, 2020, 02:45:40 pm »
avk, you should be fair and add Bart's modification of the first post, i.e. run the StringList loop from last to first.

And I also think that all tests relying on replacement of LineEnding pairs by a single LineEnding have a chance of failure because the random insertion of empty lines into the test list may bring two or more empty lines together, and in this case three (or more) line endings should have to be replaced. See my post higher up there.

I would also be interested in how the good old ReadLn method compares.

MaxCuriosus

  • Full Member
  • ***
  • Posts: 136
Re: Eliminating empty strings in TStringList when reading from text file.
« Reply #50 on: March 14, 2020, 02:49:31 pm »

I would also be interested in how the good old ReadLn method compares.

So do I.

Bart

  • Hero Member
  • *****
  • Posts: 5538
    • Bart en Mariska's Webstek
Re: Eliminating empty strings in TStringList when reading from text file.
« Reply #51 on: March 14, 2020, 03:14:07 pm »
If a discussion about strings goes on long enough, a RegEx solution will pop up eventually.
At which point the thread spirals out of control.
And you are what? its reminder to make an appearance?

Yes, you've got me there  >:D

Bart

avk

  • Hero Member
  • *****
  • Posts: 771
Re: Eliminating empty strings in TStringList when reading from text file.
« Reply #52 on: March 14, 2020, 03:27:28 pm »
avk, you should be fair and add Bart's modification of the first post, i.e. run the StringList loop from last to first.

Sorry, I somehow overlooked this variant.
Now the results look like this:
Code: Text  [Select][+][-]
  1. RemoveEmptyLinesMax     elapsed time(ms): 3655
  2. RemoveEmptyLinesBart    elapsed time(ms): 2499
  3. RemovEmptyLinesThaddy   elapsed time(ms): 52 (failure)
  4. RemoveEmptyLinesWinny   elapsed time(ms): 3098
  5. RemoveEmptyLinesAvk     elapsed time(ms): 41
  6. RemoveEmptyLinesJamie   elapsed time(ms): 54 (failure)
  7.  
About ReadLn a bit later.

eljo

  • Sr. Member
  • ****
  • Posts: 468
Re: Eliminating empty strings in TStringList when reading from text file.
« Reply #53 on: March 14, 2020, 03:39:54 pm »
Code: Pascal  [Select][+][-]
  1. { TeljoStringList }
  2.  
  3. TeljoStringList = class(TStringList)
  4. private
  5.   FIgnoreEmptyLines: Boolean;
  6.   procedure SetIgnoreEmptyLines(AValue: Boolean);
  7. public
  8.   function Add(const S: string): Integer; override;
  9.   property IgnoreEmptyLines :Boolean read FIgnoreEmptyLines write SetIgnoreEmptyLines;
  10. end;
  11.  
  12. { TeljoStringList }
  13.  
  14. procedure TeljoStringList.SetIgnoreEmptyLines(AValue: Boolean);
  15. begin
  16.   if FIgnoreEmptyLines = AValue then Exit;
  17.   FIgnoreEmptyLines := AValue;
  18. end;
  19.  
  20. function TeljoStringList.Add(const S: string): Integer;
  21. begin
  22.   if (FIgnoreEmptyLines) and (s = '') then exit(-1);
  23.   Result := inherited Add(S);
  24. end;
  25.  
  26. procedure OpenTextFile(const aList:TEljoStringList; aFilename:String; IgnoreEmptyLines:Boolean = True);
  27. begin
  28.   aList.IgnoreEmptylines := IgnoreEmptyLines;
  29.   aList.LoadFromFile(aFilename);
  30. end;
  31.  
there that should be fast enough.

jamie

  • Hero Member
  • *****
  • Posts: 6836
Re: Eliminating empty strings in TStringList when reading from text file.
« Reply #54 on: March 14, 2020, 03:42:09 pm »
Please supply a file with know count that fails...

If you have lines with spaces but not content or even tabs etc, those are not empty lines.

I didn't have any failed results ..
The only true wisdom is knowing you know nothing

eljo

  • Sr. Member
  • ****
  • Posts: 468
Re: Eliminating empty strings in TStringList when reading from text file.
« Reply #55 on: March 14, 2020, 03:43:09 pm »
Please supply a file with know count that fails...

If you have lines with spaces but not content or even tabs etc, those are not empty lines.

I didn't have any failed results ..
try running it in a file with 2 or more empty lines grouped together.

jamie

  • Hero Member
  • *****
  • Posts: 6836
Re: Eliminating empty strings in TStringList when reading from text file.
« Reply #56 on: March 14, 2020, 03:48:27 pm »
There is no difference between getting it from a MEMO over a file, it does not fail with the demo I supplied from a memo so I would guess that maybe something else is wrong..

 There needs to be a terminating #0 at the end.

 You can't use a stringlist to lost this because as I said before the stringlist does not give you access point to a single chunk of memory, instead it breaks all the lines up using managed strings.

 The GetText and Text function recreates a single string from all that, that takes time to build and if you use the pointer from that source all you do is modify the secondary version of it with no regard of updating the original source.

 Of course you could also write it back but that then takes time.

 I'll create a text file myself using notepad, I am sure there is no #0 at the end.

The only true wisdom is knowing you know nothing

jamie

  • Hero Member
  • *****
  • Posts: 6836
Re: Eliminating empty strings in TStringList when reading from text file.
« Reply #57 on: March 14, 2020, 04:08:16 pm »
I modified the test code to load a test file.. You'll see in the button2 event that I added a #0 at the end of the file to give it a nul..
 The code works as expected..

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     Button2: TButton;
  17.     Memo1: TMemo;
  18.     procedure Button1Click(Sender: TObject);
  19.     procedure Button2Click(Sender: TObject);
  20.   private
  21.  
  22.   public
  23.  
  24.   end;
  25.  
  26. var
  27.   Form1: TForm1;
  28.  
  29. implementation
  30.  
  31. {$R *.lfm}
  32.  
  33. { TForm1 }
  34. Procedure RemoveEmptyLines( Var S:TMemorystream);
  35. var
  36.   R,W,ST:Pchar;
  37.   CC,LEC:Integer;
  38.   L:char;
  39. Begin
  40.   If (S = Nil)or(S.Size=0) then Exit;
  41.   R := PChar(S.Memory);
  42.   W := R;
  43.   ST := W;
  44.   While R^<>#0 do
  45.    Begin
  46.     CC := 0; //Char Count;
  47.     While Not (R^ in [#13,#10,#0]) do //Move line content if any
  48.      Begin
  49.       W^ := R^;
  50.       Inc(R); Inc(W);
  51.       Inc(CC);  //Char count
  52.      End;
  53.     If CC <> 0 Then
  54.     Begin
  55.     LEC := 0;  //Line Ending Count
  56.     L := #0;   //Last char in line ending.
  57.     While (R^ in [#13,#10])and(L <> R^)And(LEC<2) Do //Move the Line Ending if Valid content.
  58.      Begin
  59.       L := R^; //Update the last Line ending type incase we have single types.
  60.       Inc(LEC);
  61.       W^:= R^;
  62.       Inc(R);
  63.       Inc(W);
  64.      end;
  65.     End
  66.     Else
  67.      While (R^ in [#13,#10]) Do Inc(R); // Skip over blanks.
  68.    End;
  69.  W^ := #0; // Terminate the end;..
  70. End;
  71. procedure TForm1.Button1Click(Sender: TObject);
  72. Var
  73.   S:TMemoryStream;
  74.   P:PChar;
  75. begin
  76.    //Test code;
  77.    S := TmemoryStream.Create; //you can load from file here.
  78.    S.Write(Pchar(Memo1.Lines.Text)^,Length(Memo1.Lines.Text)+1); //use a memo for now to create test data.
  79.    RemoveEmptyLines(S);  // The real work horse;
  80.    Memo1.Lines.Text :=String(S.Memory);
  81.    S.Free;
  82. end;
  83.  
  84. procedure TForm1.Button2Click(Sender: TObject);
  85. Var
  86.   S:TMemoryStream;
  87. begin
  88.   S := TmemoryStream.Create;
  89.   S.LoadFromFile('testfile.txt');
  90.   S.Seek(0,soFromEnd);
  91.   S.WriteByte(0);
  92.   RemoveEmptyLines(S);
  93.   Memo1.Lines.Text := String(S.Memory);
  94.   S.Free;
  95. end;
  96.  
  97. end.
  98.  
  99.  

also as indicated before, Spaces and control characters does not give you a blank line.
The only true wisdom is knowing you know nothing

avk

  • Hero Member
  • *****
  • Posts: 771
Re: Eliminating empty strings in TStringList when reading from text file.
« Reply #58 on: March 14, 2020, 04:31:43 pm »
@jamie, I've changed the code, but it doesn't seem to get any better, look for yourself.

The code with lines loaded from the file looks like this:
Code: Pascal  [Select][+][-]
  1. program test_del_empty;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$modeswitch nestedprocvars}
  5.  
  6. uses
  7.   Classes, SysUtils, DateUtils, StrUtils, LGUtils, LGStrHelpers;
  8.  
  9. type
  10.   TTestProc = function: TStringList;
  11.  
  12. var
  13.   CurrProc: string = '';
  14.  
  15. const
  16.   TestFile = 'data.txt';
  17.  
  18. procedure RemoveEmptyLinesMax(aList: TStringList);
  19. var
  20.   I: Integer = 0;
  21. begin
  22.   while I < aList.Count do
  23.     if aList[I] = '' then
  24.       aList.Delete(I)
  25.     else
  26.       Inc(I);
  27. end;
  28.  
  29. function DelEmptyLinesMax: TStringList;
  30. begin
  31.   CurrProc := {$I %currentroutine%};
  32.   Result := TStringList.Create;
  33.   Result.LoadFromFile(TestFile);
  34.   RemoveEmptyLinesMax(Result);
  35. end;
  36.  
  37. procedure RemoveEmptyLinesBart(aList: TStringList);
  38. var
  39.   I: Integer;
  40. begin
  41.   for I := Pred(aList.Count) downto 0 do
  42.     if aList[I] = '' then
  43.       aList.Delete(I);
  44. end;
  45.  
  46. function DelEmptyLinesBart: TStringList;
  47. begin
  48.   CurrProc := {$I %currentroutine%};
  49.   Result := TStringList.Create;
  50.   Result.LoadFromFile(TestFile);
  51.   RemoveEmptyLinesBart(Result);
  52. end;
  53.  
  54. procedure RemovEmptyLinesThaddy(aList: TStringList);
  55. var
  56.   a: array of string;
  57. begin
  58.   a := aList.Text.Split(LineEnding, TStringSplitOptions.ExcludeEmpty);
  59.   aList.Clear;
  60.   aList.AddStrings(a);
  61. end;
  62.  
  63. function DelEmptyLinesThaddy: TStringList;
  64. begin
  65.   CurrProc := {$I %currentroutine%};
  66.   Result := TStringList.Create;
  67.   Result.LoadFromFile(TestFile);
  68.   RemovEmptyLinesThaddy(Result);
  69. end;
  70.  
  71. procedure RemoveEmptyLinesWinny(aList: TStringList);
  72. var
  73.   s: string;
  74.   p: integer = 1;
  75. begin
  76.   s := aList.Text;
  77.   repeat
  78.     p := posEX(LineEnding + LineEnding, s, p);
  79.     if p > 0 then
  80.       delete(s, p, length(lineEnding));
  81.     until p = 0;
  82.   aList.Text := s;
  83. end;
  84.  
  85. function DelEmptyLinesWinny: TStringList;
  86. begin
  87.   CurrProc := {$I %currentroutine%};
  88.   Result := TStringList.Create;
  89.   Result.LoadFromFile(TestFile);
  90.   RemoveEmptyLinesWinny(Result);
  91. end;
  92.  
  93. procedure RemoveEmptyLinesAvk(aList: TStringList);
  94. var
  95.   sb: specialize TGAutoRef<TStringBuilder>;
  96.   function NonEmpty(constref s : string): Boolean;begin Result := s <> '' end;
  97.   procedure Add(constref s: string); begin with sb.Instance do begin
  98.     Append(s); Append(LineEnding) end end;
  99. begin
  100.   aList.GetEnumerable.Select(@NonEmpty).ForEach(@Add);
  101.   aList.Text := sb.Instance.ToString;
  102. end;
  103.  
  104. function DelEmptyLinesAvk: TStringList;
  105. begin
  106.   CurrProc := {$I %currentroutine%};
  107.   Result := TStringList.Create;
  108.   Result.LoadFromFile(TestFile);
  109.   RemoveEmptyLinesAvk(Result);
  110. end;
  111.  
  112. function DelEmptyLinesJamie: TStringList;
  113.   procedure RemoveEmptyLines(var S: TMemorystream);
  114.   var
  115.     R,W,ST:Pchar;
  116.     CC,LEC:Integer;
  117.     L:char;
  118.   Begin
  119.     If (S = Nil)or(S.Size=0) then Exit;
  120.     R := PChar(S.Memory);
  121.     W := R;
  122.     ST := W;
  123.     While R^<>#0 do
  124.      Begin
  125.       CC := 0; //Char Count;
  126.       While Not (R^ in [#13,#10,#0]) do //Move line content if any
  127.        Begin
  128.         W^ := R^;
  129.         Inc(R); Inc(W);
  130.         Inc(CC);  //Char count
  131.        End;
  132.       If CC <> 0 Then
  133.       Begin
  134.       LEC := 0;  //Line Ending Count
  135.       L := #0;   //Last char in line ending.
  136.       While (R^ in [#13,#10])and(L <> R^)And(LEC<2) Do //Move the Line Ending if Valid content.
  137.        Begin
  138.         L := R^; //Update the last Line ending type incase we have single types.
  139.         Inc(LEC);
  140.         W^:= R^;
  141.         Inc(R);
  142.         Inc(W);
  143.        end;
  144.       End
  145.       Else
  146.        While (R^ in [#13,#10]) Do Inc(R); // Skip over blanks.
  147.      End;
  148.      W^ := #0; // Terminate the end;..
  149.   end;
  150. var
  151.   S:TMemoryStream;
  152. begin
  153.   CurrProc := {$I %currentroutine%};
  154.   S := TMemoryStream.Create;
  155.   S.LoadFromFile(TestFile);
  156.   S.Seek(0,soFromEnd);
  157.   S.WriteByte(0);
  158.   RemoveEmptyLines(S);  // The real work horse;
  159.   Result := TStringList.Create;
  160.   Result.Text := string(S.Memory);
  161.   S.Free;
  162. end;
  163.  
  164. function DelEmptyLinesEgsuh: TStringList;
  165. var
  166.   f: TextFile;
  167.   s: string;
  168. begin
  169.   CurrProc := {$I %currentroutine%};
  170.   Result := TStringList.Create;
  171.   AssignFile(f, TestFile);
  172.   Reset(f);
  173.   while not eof(f) do begin
  174.     Readln(f, s);
  175.     if trim (s) <> '' then Result.Append(s);
  176.   end;
  177.   CloseFile(f);
  178. end;
  179.  
  180. function NonEmptyCount(aList: TStringList): Integer;
  181. var
  182.   I: Integer;
  183. begin
  184.   Result := 0;
  185.   for I := 0 to Pred(aList.Count) do
  186.     Inc(Result, Ord(aList[I] <> ''));
  187. end;
  188.  
  189. function HasEmptyLines(aList: TStringList): Boolean;
  190. var
  191.   I: Integer;
  192. begin
  193.   for I := 0 to Pred(aList.Count) do
  194.     if aList[I] = '' then
  195.       exit(True);
  196.   Result := False;
  197. end;
  198.  
  199. const
  200.   TestSize = 200000;
  201.   LineSize = 16;
  202.  
  203. function CreateStringList: TStringList;
  204.   function RandomString: string;
  205.   var
  206.     I: Integer;
  207.     p: PChar;
  208.   const
  209.     AlphabetLen = 64;
  210.     Alphabet: PChar = '1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_ ';
  211.   begin
  212.     SetLength(Result, LineSize);
  213.     p := PChar(Result);
  214.     for I := 0 to Pred(LineSize) do
  215.       p[I] := Alphabet[Random(AlphabetLen)];
  216.   end;
  217. var
  218.   I: Integer;
  219. begin
  220.   RandSeed := 1001007;
  221.   Result := TStringList.Create;
  222.   Result.Capacity := TestSize;
  223.   for I := 1 to TestSize do
  224.     if Random(5) <> 0 then
  225.       Result.Add(RandomString)
  226.     else
  227.       Result.Add('');
  228. end;
  229.  
  230. var
  231.   Proc: TTestProc = nil;
  232.   Start: TTime;
  233.   Elapsed, TestCount: Integer;
  234.   TestList: TStringList;
  235.  
  236. const Procs: array of TTestProc = (
  237.   @DelEmptyLinesMax, @DelEmptyLinesBart, @DelEmptyLinesThaddy, @DelEmptyLinesWinny,
  238.   @DelEmptyLinesAvk, @DelEmptyLinesJamie,@DelEmptyLinesEgsuh);
  239.  
  240. begin
  241.   TestList := TStringList.Create;
  242.   TestList.LoadFromFile(TestFile);
  243.   TestCount := NonEmptyCount(TestList);
  244.   TestList.Free;
  245.   for Proc in Procs do
  246.     begin
  247.       Start := Time;
  248.       TestList := Proc();
  249.       Elapsed := MillisecondsBetween(Time, Start);
  250.       if HasEmptyLines(TestList) or (TestList.Count <> TestCount) then
  251.         Writeln(CurrProc, #9'elapsed time(ms): ', Elapsed, ' (failure)')
  252.       else
  253.         Writeln(CurrProc, #9'elapsed time(ms): ', Elapsed);
  254.       TestList.Free;
  255.     end;
  256. end.
  257.  
 

and results:
Code: Pascal  [Select][+][-]
  1. DelEmptyLinesMax        elapsed time(ms): 3593
  2. DelEmptyLinesBart       elapsed time(ms): 2619
  3. DelEmptyLinesThaddy     elapsed time(ms): 78 (failure)
  4. DelEmptyLinesWinny      elapsed time(ms): 3287
  5. DelEmptyLinesAvk        elapsed time(ms): 68
  6. DelEmptyLinesJamie      elapsed time(ms): 24 (failure)
  7. DelEmptyLinesEgsuh      elapsed time(ms): 79
  8.  

jamie

  • Hero Member
  • *****
  • Posts: 6836
Re: Eliminating empty strings in TStringList when reading from text file.
« Reply #59 on: March 14, 2020, 04:39:14 pm »
I have no idea what you are using for a test file, it works here...

Please provide a file!!!!!!!!!!!!!!!!!!!!

You obviously are using something that looks like a blank line but isn't...
The only true wisdom is knowing you know nothing

 

TinyPortal © 2005-2018