TStringList
Class dùng để lưu danh sách các string
Class dùng để lưu danh sách các string
TStringList là class rất thường xuyên sử dụng trong lập trình Delphi. Việc nắm rõ cách sử dụng class này sẽ giúp bạn rất nhiều trong việc tổ chức, sắp xếp dữ liệu trong chương trình.
Về cơ bản, TStringList là một class con của lớp ảo TStrings. Vì lớp TStrings là lớp ảo nên không thể sử dụng trực tiếp mà phải dựa vào lớp con TStringList.
TStringList có thể sử dụng dưới hai dạng: một danh sách các string có thứ tự, hoặc là một danh sách dạng từ điển (dictionary) với khóa (key) và giá trị (value). Trong phần sau, chúng ta sẽ đi sâu vào vấn đề này.
Unit: System.Classes
Như mọi class khác, ta có thể khởi tạo TStringList theo cách mới sau (từ Delphi 10.3 Rio)
begin
var NewList := TStringList.Create;
try
// Do some thing with NewList
finally
NewList.Free;
end;
end;
Đây là cách khởi tạo class mới được Delphi 10.3 hỗ trợ. Từ khóa var có thể đặt bên trong khối begin end. Đối không cần khai báo kiểu dữ liệu vì đối tượng được tạo dựa trên class nên đối tượng sẽ mang kiểu class.
Hoặc bạn có thể sử dụng cách khởi tạo cũ cho các phiên bản Delphi cũ hơn (lưu ý cách này vẫn được hỗ trợ bởi Delphi 10.3)
var
NewList: TStringList;
begin
NewList := TStringList.Create;
try
// Do some thing with NewList
finally
NewList.Free;
end;
end;
Lưu ý, khi sử dụng TStringList và các class khác khởi tạo bằng phương thức Create, thì bạn phải đặt nó vào khối try finally và Free nó trong finally. Điều này là cần thiết vì bạn phải giải phóng đối tượng khi sử dụng xong nếu không sẽ bị tràn bộ nhớ. Xem thêm bài Quản lý bộ nhớ để biết thêm.
Các lệnh xử lí đối với NewList thì được đặt trong khối try finally.
Bạn có thể sử dụng nhanh cách sau để lấy một string bất kì ở vị trí yêu cầu trong list
ShowMessage(NewList[1]);
Code trên là để hiển thị string thứ 2 của danh sách. TStringList trong delphi sắp xếp thứ tự bắt đầu từ 0, nên số 1 là thứ 2, ...
Để lặp hết stringlist, bạn có thể sử dụng kĩ thuật sau
for var i: Integer := 0 to NewList.Count - 1 do
ShowMessage(NewList[i]);
// Hoặc làm gì đó khác với NewList[i]
Nâng cao: Delphi sử dụng thuộc tính NewList.Strings để lưu trữ các string nên chính xác của NewList[1] phải là NewList.Strings[1]. Vì thuộc tính Strings là default (mặc định) nên ta có thể truy cập nhanh nó thông qua tên NewList mà không phải ghi NewList.Strings rườm rà. Điều này giúp tiết kiệm thời gian và cũng làm mã dễ đọc hơn.
Một tính năng rất hay của TStringList là có thể chuyển đổi nhanh từ nhiều string thành 1 string bằng thuộc tính Text.
Điều này có ý nghĩa, đối với memo có thuộc tính Lines (TString) ta có thể gán nhanh vào Memo1.Lines
Memo1.Lines := NewList;
Nhưng với TLabel, ta không thể gán như thế được vì label không có thuộc tính Lines, thay vào đó, ta sử dụng
Label1.Caption := NewList.Text;
Gán caption của label bằng text của stringlist. Bạn yên tâm vì các dấu xuống hàng đều được mã hóa luôn lại nên không lo không xuống hàng được nhé.
Một ý nghĩa khác là bạn có thể hiện toàn bộ TStringList bằng ShowMessage. Khác với ở phần A phải sử dụng vòng lặp for để hiển thị, lần này ta trực tiếp hiển thị luôn.
ShowMessage(NewList.Text);
NewList.Add('My name is Vu');
var s: string = 'Hello';
NewList.Add(s);
Gọi phương thức NewList.Add với một tham số string như ví dụ trên để thêm một string vào danh sách. Phương thức này trả về một số nguyên là vị trí của chuỗi vừa được thêm vào, là vị trí cuối danh sách.
NewList.Insert(0, 'This is first line');
Tương tự như phương thức New như thêm một tham số là vị trí cần chèn vào. Mặc định danh sách được đếm từ 0, nên chèn vào vị trí đầu tiên là 0, chèn vào vị trí thứ hai là 1, ...
Lưu ý: Cẩn thận khi dùng hàm Insert, vị trí cần chèn cần nằm trong danh sách, nghĩa là nhỏ hơn số lượng phần tử. Ví dụ nếu list chỉ có 3 phần tử như insert vào vị trí 5 thì sẽ gây ra một lỗi.
NewList.Delete(0);
Dùng để xóa một phần tử ở vị trí xác định trong danh sách.
Phương thức này khá giống Insert, bạn cần phải chú ý đến giới hạn của vị trí cần xóa. Nếu vượt ra ngoài danh sách thì sẽ gây ra lỗi. Danh sách cũng đếm số thứ tự từ 0.
NewList.Clear;
Xóa các string trước đó đã có trong list
var OldList := TStringList.Create;
var NewList := TStringList.Create;
try
OldList.Add('OLD OLD');
NewList.AddStrings(OldList);
finally
OldList.Free;
NewList.Free;
end;
Chú ý dòng thứ 5. Ta sử dụng phương thức AddStrings để nối OldList vào NewList.
NewList.Move(0, 1);
Đổi chỗ hai string ở vị trí 1 và 2.
TStringList cung cấp một cách dễ dàng để tải dữ liệu trong file có sẵn. Ví dụ, bạn có 1 file .txt lưu danh sách các tên bạn bè, bạn muốn tải danh sách đó từ file lên TStringList ? Delphi cung cấp phương thức LoadFromFile để dễ dàng cho việc đó.
NewList.LoadFromFile('C:\BanBe.txt');
Bạn không cần quan tâm đến encoding khi load từ file. Bởi vì encoding sẽ tự động được xác định đối với mỗi file.
Đi cùng với phương thức LoadFromFile là SaveToFile để lưu dữ liệu của danh sách vào file.
NewList.SaveToFile('C:\BanBe.txt');
NewList.SaveToFile('C:\BanBeNew.txt', TEncoding.UTF8);
Khác với LoadFromFile, SaveToFile có thể có thêm tham số thứ hai là cách mã hóa (encoding) văn bản để lưu vào file. Tham số này giúp file mở ra được chính xác, mình khuyên nên sử dụng nó.
Nếu thuộc tính NewList.DefaultEncoding đã được đặt thì SaveToFile sẽ lấy giá trị đó để làm encoding.
Xem thêm phần cuối bài này để hiểu rõ hơn về encoding.
NewList.Sort;
Để sắp xếp danh sách ta sử dụng phương thức Sort. Mặc định, hàm này sẽ sắp xếp các chuỗi theo thứ tự từ A-Z. Để sử dụng danh sách giảm dần, bạn có thể sử dụng vòng lặp for downto để lặp từ cuối lên đầu list.
Write(NewList.IndexOf('ABC'));
Hàm IndexOf nhận vào một string, trả lại vị trí tìm thấy của string đó trong list. Nếu không tìm thấy sẽ trả về -1
TStringList có một tính năng khá hay là lưu dữ liệu dưới dạng dictionary. Ví dụ, bạn có một danh sách từ điển Anh - Việt như sau
Apple=Trái Táo
Dog=Con chó
...
Và bạn muốn xây dựng một hàm, kiểu như truyền vào tiếng Anh thì sẽ cho ra string tiếng Việt dựa vào file có sẵn (C:\AV.txt)
Và đây là code mẫu cho trường hợp trên
function ToVN(EN: string): string;
begin
var Dic := TStringList.Create;
try
Dic.DefaultEncoding := TEncoding.UTF8;
Dic.LoadFromFile('C:\AV.txt');
Dic.NameValueSeparator := '=';
Result := Dic.Values[EN];
finally
Dic.Free;
end;
end;
Khi sử dụng TStringList dạng Dictionary, bạn cần chú ý đến hai điều:
Thuộc tính NameValueSeparator: đây là một kí tự dùng để phân cách giữa key và value, ở ví dụ trên là dấu bằng (=). Lưu ý, trong danh sách dấu bằng cần đặt sát vào từ, không được cách ra.
Thuộc tính KeyNames: Sử dụng bằng cách truyền vào một Index, ở ví dụ trên, nếu gọi Dic.KeyNames[1] sẽ là Dog
Thuộc tính Values: Sử dụng bằng cách truyền vào một giá trị làm key, kết quả trả về là value tương ứng với key đó.
ValueFromIndex: Nhận vào một số là vị trí, trả về string là value ở vị trí đó.
Encoding quy định các kí tự của TStringList sẽ được lưu trữ như thế nào (theo encoding nào).
Một số encoding thường gặp: ANSI, UTF8, UTF16, Unicode, ...
Mẹo: Bạn có thể tìm kiếm về encoding trên google
Ví dụ, ANSI encoding không thể lưu được các văn bản tiếng Việt (như ă ấ, ...) mà chỉ lưu được các chữ cái tiếng Anh (abc). Các kí tự khác sẽ được thay thế bằng dấu chấm hỏi (?). UTF8, UTF16 có thể lưu được các kí tự tiếng Việt, nhưng UTF16 sử dụng nhiều bộ nhớ.
Trong lập trình phần mềm, người ta thường sử dụng bảng mã UTF8 làm chuẩn để lưu trữ văn bản.
Để thay đổi encoding của một TStringList, ta sử dụng thuộc tính DefaultEncoding
NewList.DefaultEncoding := TEncoding.UTF8;
TEncoding là một lớp cung cấp hầu hết các encoding dưới dạng thuộc tính. Cách sử dụng như ví dụ trên.