Difference between revisions of "TStringList-TStrings Tutorial"

From Lazarus wiki
Jump to navigationJump to search
m (→‎File Handling: resolve redlink caused by spelling mistake)
 
(43 intermediate revisions by 18 users not shown)
Line 1: Line 1:
 +
{{TString_List-TString_Tutorial}}
 
==TStringList==
 
==TStringList==
  
The TStringList(Or TStrings) is much like a fancy dynamic array or Set of Strings(Not Possible). It will come in handy alot when programming and im going to teach you basic TStringList Usage!
+
The [[doc:rtl/classes/tstringlist.html|TStringList]] (or its parent [[doc:rtl/classes/tstrings.html|TStrings]]) is much like a fancy [[Dynamic array|dynamic array]] or [[Set]] of Strings (a set of strings is not possible in FPC). It will come in handy a lot when programming and I'm going to teach you basic TStringList usage!
 
 
<Delphi>
 
Program StrList;
 
 
 
Var
 
Str:TStringList;
 
  
 +
===Simple example===
 +
<syntaxhighlight lang="pascal">
 +
program StrList;
 +
{$mode objfpc}
 +
uses
 +
Classes, SysUtils;
 +
var
 +
  Str: TStringList;
 
begin
 
begin
   Str := TStringList.Create;//This is needed when using this class(or most classes)
+
   Str := TStringList.Create; // This is needed when using this class(or most classes)
 
   Str.Add('Some String!');
 
   Str.Add('Some String!');
 +
  writeln('The stringlist now has ' + IntToStr(Str.Count) + ' string(s).');
 
   Readln;
 
   Readln;
end;
+
  Str.Free; //Release the memory used by this stringlist instance
</Delphi>
+
end.
 +
</syntaxhighlight>
  
This is a simple program(Console) that will create and add one string to a string list!
+
This is a simple [[Command-line_interface|console program]] that will create and add one string to a stringlist.
Now heres some things you should know:
+
Now here's some things you should know:
  
'''Create''' - Will create the string list for modifying.
+
'''Create''' - Will create the string list for modifying. If you use [[Constructor|<syntaxhighlight lang="pascal" inline>constructor</syntaxhighlight>]] '''Create''', you have to later '''Free'''.
 +
Calling <syntaxhighlight lang="pascal" inline>free</syntaxhighlight> causes [[Destructor|<syntaxhighlight lang="pascal" inline>destructor</syntaxhighlight>]] a <syntaxhighlight lang="pascal" inline>Destroy</syntaxhighlight> invitation and release the memory it takes. If not, you program will not crash, but it will not release all the memory it occupied: a memory leak.
  
'''Count''' - Is a counter for the amount of strings in the List. It is a '''zero based counter'''
+
'''Count''' - This [[Property|property]] is a counter for the number of strings in the List.
  
'''Add''' - Will allow you to add one string to the string list. It is a Function that will return the '''Index''' of the String. This is Were the counter comes in handy.
+
'''Add''' - This [[Method|method]] allows you to add one string to the stringlist. It is a function that will return the '''Index''' of the String. This is where the counter comes in handy.
  
'''Delete''' - Will delete a string from the string list. Just know that you do not simply input the string, you have to input the index of the string.(Like I said. Its like a fancy Dynamic Array)
+
'''Delete''' - Will delete a string from the stringlist. Just know that you do not simply input the string, you have to input the index of the string. Like I said: it's like a fancy Dynamic Array.
  
'''IndexOf''' - Will allow you to return the index of the string in the list. If it is not found it returns -1.
+
'''IndexOf''' - Will return the index of the string in the list. If it is not found it returns -1.
  
 
'''Clear''' - Will clear the list.
 
'''Clear''' - Will clear the list.
  
===Example===
+
===Expanded Example===
 +
 
 +
How about a more juicy example, eh?
 +
 
 +
<syntaxhighlight lang="pascal">
 +
program StrList2;
 +
{$mode ObjFPC}
 +
uses
 +
Classes, SysUtils;
 +
 
 +
var
 +
  Str: TStringList;
 +
  S: String;
 +
  Counter: Integer;
 +
begin
 +
  Str := TStringList.Create;
 +
  Writeln('String List Test');
 +
  repeat
 +
    Writeln('Enter a string to add (type EXIT to stop adding strings)');
 +
    Readln(S);
 +
    if (S = 'EXIT') then
 +
      Break; // exit the loop
 +
   
 +
    if (S <> '') then
 +
    begin
 +
      Counter := Str.Add(S);
 +
      Writeln('String: ' + S + ' was Added!');
 +
      Writeln('Index is: ' + IntToStr(Counter)); // The counter will always become the index of the last thing added
 +
    end
 +
    else
 +
    begin
 +
      Writeln('No data entered...');
 +
    end;
 +
  until (S = 'EXIT');
 +
  writeln('Contents of the TStringList: '+ Str.CommaText);
 +
  Str.Free; //release the memory again
 +
end.
 +
</syntaxhighlight>
 +
 
 +
However, to avoid possible memory leaks you should always use a [[Try]] - [[Finally]] block where possible for this, so you get something like:
 +
 
 +
<syntaxhighlight lang="pascal">
 +
var
 +
  slist: TStringList;
  
How about a more juicy example, Eh?
+
...
  
<Delphi>
+
slist := TStringList.Create;
 +
try
 +
  ...
 +
  // do things with your stringlist 
 +
  ...
 +
finally
 +
  if Assigned(slist) then
 +
    FreeAndNil(slist);
 +
end;
  
Program StrList;
+
</syntaxhighlight>
  
Var
+
<syntaxhighlight lang="pascal">
Str:TStringList;
+
// This works perfect, no double creation of stringlist... comments free to send to edgarrod71@gmail.com
  S:String;
+
function theStringList: TStringList;
Counter:Integer;
+
var
 +
  J: integer;
 +
begin
 +
  result := TStringList.Create;
 +
  for J:=0 to 10 do
 +
    result.add(intToStr(J));
 +
end;
  
 +
procedure Caller;
 +
var
 +
  SL: TStringList;
 +
  K: integer;
 
begin
 
begin
   Str := TStringList.Create;
+
   SL := theStringList;
   Writeln('String List Test');
+
  for K:=0 to pred(SL.Count) do
   Repeat
+
    writeln(SL[K]);
   Writeln('Input a string to add');
+
   if assigned(SL) then
  Readln(S);  
+
    SL.Free;
   IF(S = 'EXIT')Then Halt;
+
end;
  IF NOT(S = '')Then
+
</syntaxhighlight>
  begin
+
 
    Counter := Str.Add(S);
+
To iterate through the list it is better to use the '''while-do''' loop instead of the '''for-to''' loop. The reason is that the list can be empty, then the for-to loop does not work correctly.
    Writeln('String: '+S'+ was Added!');
+
In this example, SubscriberDel procedure is called for each ID in the List and the list of the IDs is passed to the procedure as a string.
     Writeln('Index is: '+InttoStr(Counter);//The counter will always become the index of the last thing added
+
 
  end Else Writeln('Nothing Inputed :D');
+
<syntaxhighlight lang="pascal">
  Until(S = 'EXIT');
+
procedure SubscribersDelete(const Subscriber_ID: string);
 +
var
 +
   List : TStringList;
 +
  i : Integer;
 +
begin
 +
  List := TStringList.Create;
 +
  List.Text := Subscriber_ID;
 +
   i := 0;
 +
  while i < List.Count do
 +
    begin
 +
      SubscriberDel(List.Strings[i]);
 +
      inc(i);
 +
    end;
 +
   List.Free;
 +
end;
 +
</syntaxhighlight>
 +
 
 +
=== Conversion to and from delimited strings ===
 +
 
 +
Code below will result in a stringlist, containing 4 elements ('1', '2', '3' and '4');
 +
<syntaxhighlight lang="pascal">
 +
procedure Sample;
 +
var
 +
    MyStringList: TStringList=nil;
 +
begin
 +
    MyStringList:= TStringList.create;
 +
    MyStringList.Delimiter := ';';
 +
    MyStringList.DelimitedText:='1;2;3;4';
 +
    MyStringList.free;
 +
end;
 +
</syntaxhighlight>
 +
 
 +
 
 +
Respectively next code will assemble a stringlist into a delimited string ('1;2;3;4'):
 +
<syntaxhighlight lang="pascal">
 +
function Sample2 : string;
 +
var
 +
    MyStringList: TStringList=nil;
 +
begin
 +
    MyStringList:= TStringList.create;
 +
    MyStringList.Delimiter := ';';
 +
    MyStringList.Add('1');
 +
    MyStringList.Add('2');
 +
    MyStringList.Add('3');
 +
    MyStringList.Add('4');
 +
    Result :=MyStringList.DelimitedText;
 +
    MyStringList.free;
 +
end; 
 +
</syntaxhighlight>
 +
 
 +
 
 +
Note that Delimter is a character, '''not''' a string!
 +
If your separator is a string (for example „\n‟), you could use code below, to get a stringlist, containing 4 elements ('1', '2', '3' and '4'):
 +
<syntaxhighlight lang="pascal">
 +
procedure Sample;
 +
var
 +
     MyStringList: TStringList=nil;
 +
begin
 +
    MyStringList:= TStringList.create;
 +
    MyStringList.text:=StringReplace('1\n2\n3\n4','\n',Lineending,[rfReplaceAll, rfIgnoreCase]);
 +
    MyStringList.free;
 +
end;
 +
</syntaxhighlight>
 +
 
 +
Vice versa, next [[Function|function]] will return „1\n2\n3‟:
 +
<syntaxhighlight lang="pascal">
 +
Function Sample : string;
 +
var
 +
    MyStringList: TStringList=nil;
 +
begin
 +
    MyStringList:= TStringList.create;
 +
    MyStringList.SkipLastLineBreak := True;
 +
    MyStringList.add('1');
 +
    MyStringList.add('2');
 +
    MyStringList.add('3');
 +
    result := StringReplace(MyStringList.Text,Lineending,'\n', [rfReplaceAll, rfIgnoreCase]);
 +
    MyStringList.free;
 
end;
 
end;
</Delphi>
+
</syntaxhighlight>
  
 
==File Handling==
 
==File Handling==
  
When using the TStringList you have 2 main file handling procedures.
+
When using the TStringList you have 2 file handling [[Procedure|procedures]]: '''SaveToFile''' and '''LoadFromFile'''.
'''SaveToFile''' And '''LoadFromFile'''
+
SavetoFile will save all strings in the list to a file.
By Using SavetoFile it will save all strings in the list to a file.
 
 
LoadFromFile will open the file and add the file data to the list string by string.
 
LoadFromFile will open the file and add the file data to the list string by string.
  
<Delphi>
+
<syntaxhighlight lang="pascal">
Var
+
program StrListFile;
  Str:TStringList;
+
{$mode objfpc}
 +
uses
 +
  Classes, SysUtils;
 +
 
 +
var
 +
  Str: TStringList;
 
begin
 
begin
 
   Str := TStringList.Create;
 
   Str := TStringList.Create;
   Str.LoadFromFile('SomeFile.txt');
+
   try
  Str.Add('Hello');
+
    Str.LoadFromFile('SomeFile.txt');
  Str.SaveToFile('SomeFile.txt');
+
    Str.Add('Hello');
end;
+
    Str.SaveToFile('SomeFile.txt');
</Delphi>
+
  finally
 +
    Str.Free;
 +
  end;
 +
end.
 +
</syntaxhighlight>
 +
 
 +
You just opened a file, edited it and saved it right back to were it was!
 +
 
 +
== Sorting ==
 +
 
 +
The Find procedure requires that the list be sorted.  The easiest approach is to set its Sorted property to True, then new items added to the list will be inserted in the correct position. This has a few extra side effects, firstly, you cannot use the Insert() procedure, use only Add(). Secondly, it sets the Duplicates property, its default setting is "dupIgnore" which means attempts to Add identical entries will be ignored.  However, calls to AddObject() that have an identical string and a new Object, the new Object replaces the existing one.
 +
 
 +
==Dynamic string array comparison==
 +
 
 +
TStringList is simply an [[object-oriented programming|object-oriented]] version of a dynamic string array. Some methods have analogs:
 +
 
 +
{| class="wikitable"
 +
|-
 +
! Operation !! array of string !! TStringList
 +
|-
 +
| Variable declaration || StringList: array of string; || StringList: TStringList;
 +
|-
 +
| Initialization || implicit constructor || StringList := TStringList.Create
 +
|-
 +
| Set size || SetLength(StringList, X); || StringList.Size := X;
 +
|-
 +
| Get size || X := Length(StringList); || X := StringList.Count;
 +
|-
 +
| Add item || SetLength(StringList, Length(StringList) + 1); StringList[Length(StringList) - 1] := X; || StringList.Add(X);
 +
|-
 +
| Delete item || for I := Index to Length(StringList) - 2 do StringList[I] := StringList[I + 1]; SetLength(StringList, Length(StringList) - 1); || StringList.Delete(Index);
 +
|-
 +
| Remove all items || SetLength(StringList, 0); || StringList.Clear;
 +
|-
 +
| Finalization || implicit destructor || StringList.Free;
 +
|}
 +
 
 +
However, TStringList offers much more functionality than a basic structure such as a dynamic array.
  
You just opened a file,edited it and saved it right back to were it was!
+
==Keep Learning==
 +
TStringList has many other interesting features:
 +
# It allows you to sort the strings
 +
# It allows you to limit the list to only unique strings
 +
# You can get the text of all strings as a single string using the '''Text''' property.
 +
# You can store an object or other data next to the string
  
===Keep Learning===
+
You can learn all the different procedures, functions and properties. See [[doc:rtl/classes/tstringlist.html|TStringList documentation]]... or the help in Lazarus.
You can learn all the different procedures,functions and property's Here: [http://www.freepascal.org/docs-html/rtl/classes/tstringlist.html]
 
  
IF you feel i might have left something out, '''Modify At Will!'''
+
... and you might like to extend this tutorial if you feel like it.
  
Hope I helped!
+
== See also ==
 +
* [[Character and string types]]

Latest revision as of 15:39, 10 August 2022

Deutsch (de) English (en) español (es) suomi (fi) français (fr) polski (pl) русский (ru)

TStringList

The TStringList (or its parent TStrings) is much like a fancy dynamic array or Set of Strings (a set of strings is not possible in FPC). It will come in handy a lot when programming and I'm going to teach you basic TStringList usage!

Simple example

program StrList;
{$mode objfpc}
uses
 Classes, SysUtils;
var
  Str: TStringList;
begin
  Str := TStringList.Create; // This is needed when using this class(or most classes)
  Str.Add('Some String!');
  writeln('The stringlist now has ' + IntToStr(Str.Count) + ' string(s).');
  Readln;
  Str.Free; //Release the memory used by this stringlist instance
end.

This is a simple console program that will create and add one string to a stringlist. Now here's some things you should know:

Create - Will create the string list for modifying. If you use constructor Create, you have to later Free. Calling free causes destructor a Destroy invitation and release the memory it takes. If not, you program will not crash, but it will not release all the memory it occupied: a memory leak.

Count - This property is a counter for the number of strings in the List.

Add - This method allows you to add one string to the stringlist. It is a function that will return the Index of the String. This is where the counter comes in handy.

Delete - Will delete a string from the stringlist. Just know that you do not simply input the string, you have to input the index of the string. Like I said: it's like a fancy Dynamic Array.

IndexOf - Will return the index of the string in the list. If it is not found it returns -1.

Clear - Will clear the list.

Expanded Example

How about a more juicy example, eh?

program StrList2;
{$mode ObjFPC}
uses
Classes, SysUtils;

var
  Str: TStringList;
  S: String;
  Counter: Integer;
begin
  Str := TStringList.Create;
  Writeln('String List Test');
  repeat
    Writeln('Enter a string to add (type EXIT to stop adding strings)');
    Readln(S); 
    if (S = 'EXIT') then 
      Break; // exit the loop
    
    if (S <> '') then
    begin
      Counter := Str.Add(S);
      Writeln('String: ' + S + ' was Added!');
      Writeln('Index is: ' + IntToStr(Counter)); // The counter will always become the index of the last thing added
    end 
    else 
    begin
      Writeln('No data entered...');
    end;
  until (S = 'EXIT');
  writeln('Contents of the TStringList: '+ Str.CommaText);
  Str.Free; //release the memory again
end.

However, to avoid possible memory leaks you should always use a Try - Finally block where possible for this, so you get something like:

var
  slist: TStringList;

...

slist := TStringList.Create;
try
  ...
  // do things with your stringlist  
  ...
finally
  if Assigned(slist) then
    FreeAndNil(slist);
end;
// This works perfect, no double creation of stringlist... comments free to send to edgarrod71@gmail.com
function theStringList: TStringList;
var
 J: integer;
begin
  result := TStringList.Create;
  for J:=0 to 10 do
    result.add(intToStr(J));
end;

procedure Caller;
var
  SL: TStringList;
  K: integer;
begin
  SL := theStringList;
  for K:=0 to pred(SL.Count) do
    writeln(SL[K]);
  if assigned(SL) then
    SL.Free;
end;

To iterate through the list it is better to use the while-do loop instead of the for-to loop. The reason is that the list can be empty, then the for-to loop does not work correctly. In this example, SubscriberDel procedure is called for each ID in the List and the list of the IDs is passed to the procedure as a string.

procedure SubscribersDelete(const Subscriber_ID: string);
var
  List : TStringList; 
  i : Integer;
begin
  List := TStringList.Create;
  List.Text := Subscriber_ID;
  i := 0;
  while i < List.Count do
    begin
      SubscriberDel(List.Strings[i]);
      inc(i);
    end;
  List.Free;
end;

Conversion to and from delimited strings

Code below will result in a stringlist, containing 4 elements ('1', '2', '3' and '4');

procedure Sample;
var
    MyStringList: TStringList=nil;
begin
     MyStringList:= TStringList.create;
     MyStringList.Delimiter := ';';
     MyStringList.DelimitedText:='1;2;3;4';
     MyStringList.free;
end;


Respectively next code will assemble a stringlist into a delimited string ('1;2;3;4'):

function Sample2 : string;
var
    MyStringList: TStringList=nil;
begin
     MyStringList:= TStringList.create;
     MyStringList.Delimiter := ';';
     MyStringList.Add('1');
     MyStringList.Add('2');
     MyStringList.Add('3');
     MyStringList.Add('4');
     Result :=MyStringList.DelimitedText;
     MyStringList.free;
end;


Note that Delimter is a character, not a string! If your separator is a string (for example „\n‟), you could use code below, to get a stringlist, containing 4 elements ('1', '2', '3' and '4'):

procedure Sample;
var
    MyStringList: TStringList=nil;
begin
     MyStringList:= TStringList.create;
     MyStringList.text:=StringReplace('1\n2\n3\n4','\n',Lineending,[rfReplaceAll, rfIgnoreCase]);
     MyStringList.free;
end;

Vice versa, next function will return „1\n2\n3‟:

Function Sample : string;
var
    MyStringList: TStringList=nil;
begin
     MyStringList:= TStringList.create;
     MyStringList.SkipLastLineBreak := True;
     MyStringList.add('1');
     MyStringList.add('2');
     MyStringList.add('3');
     result := StringReplace(MyStringList.Text,Lineending,'\n', [rfReplaceAll, rfIgnoreCase]);
     MyStringList.free;
end;

File Handling

When using the TStringList you have 2 file handling procedures: SaveToFile and LoadFromFile. SavetoFile will save all strings in the list to a file. LoadFromFile will open the file and add the file data to the list string by string.

program StrListFile;
{$mode objfpc}
uses
 Classes, SysUtils;

var
  Str: TStringList;
begin
  Str := TStringList.Create;
  try
    Str.LoadFromFile('SomeFile.txt');
    Str.Add('Hello');
    Str.SaveToFile('SomeFile.txt');
  finally
    Str.Free;
  end;
end.

You just opened a file, edited it and saved it right back to were it was!

Sorting

The Find procedure requires that the list be sorted. The easiest approach is to set its Sorted property to True, then new items added to the list will be inserted in the correct position. This has a few extra side effects, firstly, you cannot use the Insert() procedure, use only Add(). Secondly, it sets the Duplicates property, its default setting is "dupIgnore" which means attempts to Add identical entries will be ignored. However, calls to AddObject() that have an identical string and a new Object, the new Object replaces the existing one.

Dynamic string array comparison

TStringList is simply an object-oriented version of a dynamic string array. Some methods have analogs:

Operation array of string TStringList
Variable declaration StringList: array of string; StringList: TStringList;
Initialization implicit constructor StringList := TStringList.Create
Set size SetLength(StringList, X); StringList.Size := X;
Get size X := Length(StringList); X := StringList.Count;
Add item SetLength(StringList, Length(StringList) + 1); StringList[Length(StringList) - 1] := X; StringList.Add(X);
Delete item for I := Index to Length(StringList) - 2 do StringList[I] := StringList[I + 1]; SetLength(StringList, Length(StringList) - 1); StringList.Delete(Index);
Remove all items SetLength(StringList, 0); StringList.Clear;
Finalization implicit destructor StringList.Free;

However, TStringList offers much more functionality than a basic structure such as a dynamic array.

Keep Learning

TStringList has many other interesting features:

  1. It allows you to sort the strings
  2. It allows you to limit the list to only unique strings
  3. You can get the text of all strings as a single string using the Text property.
  4. You can store an object or other data next to the string

You can learn all the different procedures, functions and properties. See TStringList documentation... or the help in Lazarus.

... and you might like to extend this tutorial if you feel like it.

See also