TStringList-TStrings Tutorial/pl
│
Deutsch (de) │
English (en) │
español (es) │
suomi (fi) │
français (fr) │
polski (pl) │
русский (ru) │
TStringList
TStringList (lub jego rodzic TStrings) jest bardzo podobna do fantazyjnej tablicy dynamicznej lub zbioru ciągów typu string (typ zbiorowy ciągów znakowych nie jest możliwy w FPC). Ten typ danych jest bardzo przydatny podczas programowania i mam zamiar nauczyć Cię podstaw obsługi TStringList!
Prosty przykład
program StrList;
{$mode objfpc}
uses
Classes, SysUtils;
var
Str: TStringList;
begin
Str := TStringList.Create; // Jest to potrzebne podczas korzystania z tej klasy (lub większości klas)
Str.Add('Jakiś ciąg znaków!');
writeln('Lista ciągów ma teraz ' + IntToStr(Str.Count) + ' ciąg(ów).');
Readln;
Str.Free; //Zwolnij pamięć używaną przez tę instancję stringlist
end.
Jest to prosty program konsolowy, który utworzy i doda jeden ciąg (string) do listy ciągów (stringlist). Oto kilka rzeczy, które powinieneś wiedzieć:
Create - Stworzy listę ciągów, którą potem możesz modyfikować. Jeśli używasz konstruktora constructor
Create, musisz później zwolnić jego pamięć za pomocą Free. Wywołanie free
skutkuje wywołaniem destruktora destructor
Destroy
, który niszczy listę i uwalnia zajmowaną przez nią pamięć. Jeśli tego nie zrobisz, to program nie ulegnie awarii, ale też nie zwolni całej zajmowanej pamięci i nastąpi tzw. wyciek pamięci.
Count - Ta właściwość jest licznikiem liczby ciągów na liście.
Add - Ta metoda umożliwia dodanie jednego ciągu do listy ciągów. Jest to funkcja, która zwraca indeks ciągu. Tutaj z pomocą przychodzi licznik.
Delete - Usuwa ciąg (string) z listy ciągów (stringlist). Musisz wiedzieć, że nie podajesz ciągu znaków, które chcesz usunąć, ale musisz wprowadzić indeks tego ciągu. Jak powiedziałem: to jak fantazyjna tablica dynamiczna.
IndexOf - Zwróci indeks ciągu na liście. Jeśli nie zostanie on znaleziony, to zwraca -1.
Clear - Czyści całą listę.
Rozszerzony przykład
A może bardziej soczysty przykład, co?
program StrList2;
{$mode ObjFPC}
uses
Classes, SysUtils;
var
Str: TStringList;
S: String;
Counter: Integer;
begin
Str := TStringList.Create;
Writeln('String List Test');
repeat
Writeln('Wpisz ciąg do dodania (wpisz KONIEC, aby zatrzymać dodawanie ciągów)');
Readln(S);
if (S = 'KONIEC') then
Break; // wyjście z pętli
if (S <> '') then
begin
Counter := Str.Add(S);
Writeln('Ciąg: ' + S + ' został dodany!');
Writeln('Jego index to: ' + IntToStr(Counter)); // Licznik zawsze będzie indeksem ostatnio dodanej rzeczy
end
else
begin
Writeln('Nie wprowadzono żadnych danych...');
end;
until (S = 'KONIEC');
writeln('Zawartość TStringList: '+ Str.CommaText);
Str.Free; //zwolnij pamięć
end.
Jednak, aby uniknąć możliwych wycieków pamięci, zawsze powinieneś używać bloku Try - Finally wszędzie, gdzie to możliwe, aby uzyskać coś takiego:
var
slist: TStringList;
...
slist := TStringList.Create;
try
...
// rób różne rzeczy z twoją listą stringów (stringlist)
...
finally
if Assigned(slist) then
FreeAndNil(slist);
end;
// Działa to doskonale, bez podwójnego tworzenia listy ciągów
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;
Aby iterować po liście, lepiej jest użyć pętli while-do zamiast pętli for-to. Powodem jest to, że lista może być pusta, więc pętla for-to nie działa poprawnie.
W tym przykładzie procedura SubscriberDel jest wywoływana dla każdego identyfikatora ID na liście, a lista identyfikatorów ID jest przekazywana do procedury jako ciąg znaków (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;
Konwersja do i z ciągów rozdzielanych
Poniższy kod spowoduje powstanie listy ciągów zawierającej 4 elementy ('1', '2', '3' i '4');
procedure Sample;
var
MyStringList: TStringList=nil;
begin
MyStringList:= TStringList.create;
MyStringList.Delimiter := ';';
MyStringList.DelimitedText:='1;2;3;4';
MyStringList.free;
end;
Odpowiednio następny kod złoży listę ciągów w ciąg rozdzielony średnikami ('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;
Zwróć uwagę, że separator to znak typu char, a nie ciąg typu string! Jeśli separatorem jest ciąg (na przykład „\n”), to możesz użyć poniższego kodu, aby uzyskać listę ciągów zawierającą 4 elementy („1”, „2”, „3” i „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;
I odwrotnie, następna funkcja zwróci „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;
Obsługa plików
Korzystając z TStringList, masz do dyspozycji 2 procedury obsługi plików: SaveToFile i LoadFromFile. SavetoFile zapisze wszystkie ciągi z listy do pliku. LoadFromFile otworzy plik i doda dane pliku do listy ciągów.
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.
Właśnie otworzyłeś plik, wyedytowałeś go i zapisałeś z powrotem tam, gdzie był!
Sortowanie
Procedura Find wymaga posortowanej listy. Najłatwiejszym sposobem jest ustawienie właściwości Sorted na True, dzięki temu nowe elementy dodawane do listy zostaną wstawione we właściwej pozycji. Ma to kilka dodatkowych efektów ubocznych, po pierwsze, nie możesz użyć procedury Insert(), użyj tylko Add(). Po drugie, ustawia ona właściwość Duplicates, jej domyślne ustawienie to „dupIgnore”, co oznacza, że próby dodania identycznych wpisów będą ignorowane. Jednak wywołanie AddObject(), które mają identyczny ciąg znaków i jakiś nowy Object, spowoduje, że nowy Object zastąpi istniejący.
Porównanie z dynamiczną tablicą ciągów
TStringList to po prostu zorientowana obiektowo wersja dynamicznej tablicy ciągów. Niektóre metody mają tu nawet swoje odpowiedniki:
Operacja | Tablica ciągów | TStringList |
---|---|---|
Deklaracja zmiennych | StringList: array of string; | StringList: TStringList; |
Inicjalizacja | domyślnie constructor | StringList := TStringList.Create |
Ustawenie rozmiaru | SetLength(StringList, X); | StringList.Size := X; |
Odczytanie rozmiaru | X := Length(StringList); | X := StringList.Count; |
Dodanie elementu | SetLength(StringList, Length(StringList) + 1); StringList[Length(StringList) - 1] := X; | StringList.Add(X); |
Usunięcie elememtu | for I := Index to Length(StringList) - 2 do StringList[I] := StringList[I + 1]; SetLength(StringList, Length(StringList) - 1); | StringList.Delete(Index); |
Usunięcie wszystkich elementów | SetLength(StringList, 0); | StringList.Clear; |
Finalizacja | domyślnie destructor | StringList.Free; |
Jednak TStringList oferuje znacznie więcej funkcji niż podstawowa struktura, taka jak tablica dynamiczna.
Dalsza nauka
TStringList ma wiele innych interesujących cech:
- Pozwala na sortowanie ciągów
- Pozwala ograniczyć listę tylko do unikalnych ciągów
- Możesz pobrać tekst wszystkich ciągów jako jeden ciąg przy użyciu właściwości Text.
- Obok ciągu można przechowywać obiekt lub inne dane
Możesz nauczyć się różnych procedur, funkcji i właściwości. Zobacz dokumentacja TStringList ... lub zajrzyj do pomocy w Lazarusie.
... i możesz rozszerzyć ten samouczek, jeśli masz na to ochotę.