Sign in Join
Wiki copytemporary

TStringList-TStrings Tutorial: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: TStringList-TStrings Tutorial

OldNewLine
1+## TStringList
2+
3+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!
4+
5+### Simple example
6+
7+``` pascal
8+program StrList;
9+{$mode objfpc}
10+uses
11+ Classes, SysUtils;
12+var
13+ Str: TStringList;
14+begin
15+ Str := TStringList.Create; // This is needed when using this class(or most classes)
16+ Str.Add('Some String!');
17+ writeln('The stringlist now has ' + IntToStr(Str.Count) + ' string(s).');
18+ Readln;
19+ Str.Free; //Release the memory used by this stringlist instance
20+end.
21+```
22+
23+This is a simple [[Command-line interface|console program]] that will create and add one string to a stringlist. Now here's some things you should know:
24+
25+**Create** - Will create the string list for modifying. If you use [[Constructor|constructor]] **Create**, you have to later **Free**. Calling `free` causes [[Destructor|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.
26+
27+**Count** - This [[Property|property]] is a counter for the number of strings in the List.
28+
29+**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.
30+
31+**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.
32+
33+**IndexOf** - Will return the index of the string in the list. If it is not found it returns -1.
34+
35+**Clear** - Will clear the list.
36+
37+### Expanded Example
38+
39+How about a more juicy example, eh?
40+
41+``` pascal
42+program StrList2;
43+{$mode ObjFPC}
44+uses
45+Classes, SysUtils;
46+
47+var
48+ Str: TStringList;
49+ S: String;
50+ Counter: Integer;
51+begin
52+ Str := TStringList.Create;
53+ Writeln('String List Test');
54+ repeat
55+ Writeln('Enter a string to add (type EXIT to stop adding strings)');
56+ Readln(S);
57+ if (S = 'EXIT') then
58+ Break; // exit the loop
59+
60+ if (S <> '') then
61+ begin
62+ Counter := Str.Add(S);
63+ Writeln('String: ' + S + ' was Added!');
64+ Writeln('Index is: ' + IntToStr(Counter)); // The counter will always become the index of the last thing added
65+ end
66+ else
67+ begin
68+ Writeln('No data entered...');
69+ end;
70+ until (S = 'EXIT');
71+ writeln('Contents of the TStringList: '+ Str.CommaText);
72+ Str.Free; //release the memory again
73+end.
74+```
75+
76+However, to avoid possible memory leaks you should always use a [[Try]] - [[Finally]] block where possible for this, so you get something like:
77+
78+``` pascal
79+var
80+ slist: TStringList;
81+
82+...
83+
84+slist := TStringList.Create;
85+try
86+ ...
87+ // do things with your stringlist
88+ ...
89+finally
90+ if Assigned(slist) then
91+ FreeAndNil(slist);
92+end;
93+```
94+
95+``` pascal
96+// This works perfect, no double creation of stringlist... comments free to send to edgarrod71@gmail.com
97+function theStringList: TStringList;
98+var
99+ J: integer;
100+begin
101+ result := TStringList.Create;
102+ for J:=0 to 10 do
103+ result.add(intToStr(J));
104+end;
105+
106+procedure Caller;
107+var
108+ SL: TStringList;
109+ K: integer;
110+begin
111+ SL := theStringList;
112+ for K:=0 to pred(SL.Count) do
113+ writeln(SL[K]);
114+ if assigned(SL) then
115+ SL.Free;
116+end;
117+```
118+
119+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.
120+
121+``` pascal
122+procedure SubscribersDelete(const Subscriber_ID: string);
123+var
124+ List : TStringList;
125+ i : Integer;
126+begin
127+ List := TStringList.Create;
128+ List.Text := Subscriber_ID;
129+ i := 0;
130+ while i < List.Count do
131+ begin
132+ SubscriberDel(List.Strings[i]);
133+ inc(i);
134+ end;
135+ List.Free;
136+end;
137+```
138+
139+### Conversion to and from delimited strings
140+
141+Code below will result in a stringlist, containing 4 elements ('1', '2', '3' and '4');
142+
143+``` pascal
144+procedure Sample;
145+var
146+ MyStringList: TStringList=nil;
147+begin
148+ MyStringList:= TStringList.create;
149+ MyStringList.Delimiter := ';';
150+ MyStringList.DelimitedText:='1;2;3;4';
151+ MyStringList.free;
152+end;
153+```
154+
155+Respectively next code will assemble a stringlist into a delimited string ('1;2;3;4'):
156+
157+``` pascal
158+function Sample2 : string;
159+var
160+ MyStringList: TStringList=nil;
161+begin
162+ MyStringList:= TStringList.create;
163+ MyStringList.Delimiter := ';';
164+ MyStringList.Add('1');
165+ MyStringList.Add('2');
166+ MyStringList.Add('3');
167+ MyStringList.Add('4');
168+ Result :=MyStringList.DelimitedText;
169+ MyStringList.free;
170+end;
171+```
172+
173+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'):
174+
175+``` pascal
176+procedure Sample;
177+var
178+ MyStringList: TStringList=nil;
179+begin
180+ MyStringList:= TStringList.create;
181+ MyStringList.text:=StringReplace('1\n2\n3\n4','\n',Lineending,[rfReplaceAll, rfIgnoreCase]);
182+ MyStringList.free;
183+end;
184+```
185+
186+Vice versa, next [[Function|function]] will return „1\n2\n3‟:
187+
188+``` pascal
189+Function Sample : string;
190+var
191+ MyStringList: TStringList=nil;
192+begin
193+ MyStringList:= TStringList.create;
194+ MyStringList.SkipLastLineBreak := True;
195+ MyStringList.add('1');
196+ MyStringList.add('2');
197+ MyStringList.add('3');
198+ result := StringReplace(MyStringList.Text,Lineending,'\n', [rfReplaceAll, rfIgnoreCase]);
199+ MyStringList.free;
200+end;
201+```
202+
203+## File Handling
204+
205+When using the TStringList you have 2 file handling [[Procedure|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.
206+
207+``` pascal
208+program StrListFile;
209+{$mode objfpc}
210+uses
211+ Classes, SysUtils;
212+
213+var
214+ Str: TStringList;
215+begin
216+ Str := TStringList.Create;
217+ try
218+ Str.LoadFromFile('SomeFile.txt');
219+ Str.Add('Hello');
220+ Str.SaveToFile('SomeFile.txt');
221+ finally
222+ Str.Free;
223+ end;
224+end.
225+```
226+
227+You just opened a file, edited it and saved it right back to were it was!
228+
229+## Sorting
230+
231+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.
232+
233+## Dynamic string array comparison
234+
235+TStringList is simply an [[object-oriented programming|object-oriented]] version of a dynamic string array. Some methods have analogs:
236+
237+| Operation | array of string | TStringList |
238+|----|----|----|
239+| Variable declaration | StringList: array of string; | StringList: TStringList; |
240+| Initialization | implicit constructor | StringList := TStringList.Create |
241+| Set size | SetLength(StringList, X); | StringList.Size := X; |
242+| Get size | X := Length(StringList); | X := StringList.Count; |
243+| Add item | SetLength(StringList, Length(StringList) + 1); StringList\[Length(StringList) - 1\] := X; | StringList.Add(X); |
244+| Delete item | for I := Index to Length(StringList) - 2 do StringList\[I\] := StringList\[I + 1\]; SetLength(StringList, Length(StringList) - 1); | StringList.Delete(Index); |
245+| Remove all items | SetLength(StringList, 0); | StringList.Clear; |
246+| Finalization | implicit destructor | StringList.Free; |
247+
248+However, TStringList offers much more functionality than a basic structure such as a dynamic array.
249+
250+## Keep Learning
251+
252+TStringList has many other interesting features:
253+
254+1. It allows you to sort the strings
255+2. It allows you to limit the list to only unique strings
256+3. You can get the text of all strings as a single string using the **Text** property.
257+4. You can store an object or other data next to the string
258+
259+You can learn all the different procedures, functions and properties. See [[doc:rtl/classes/tstringlist.html|TStringList documentation]]... or the help in Lazarus.
260+
261+... and you might like to extend this tutorial if you feel like it.
262+
263+## See also
264+
265+- [[Character and string types]]
266+
267+---
268+*From the Free Pascal wiki, page "TStringList-TStrings Tutorial", as it stood on 2022-08-10 after a change by Kai Burghardt, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history