TStringList
TStringList - class được sử dụng phổ biến nhất trong Delphi
TStringList - class được sử dụng phổ biến nhất trong Delphi
TStringList là một lớp thuộc unit System.Classes, được sử dụng khá thường xuyên. TStringList cơ bản bao gồm nhiều chuỗi (string) liên tiếp nhau, phân cách bởi kí tự sLineBreak (ngắt dòng).
TStringList là lớp con của TStrings. Lớp TStrings là lớp ảo nên bạn không thể sử dụng được mà phải dùng lớp con của nó là TStringList.
TStringList có 2 cách sử dụng: một là sử dụng như một danh sách các string, hay là sử dụng dạng từ điển với hai trường Key (khóa) và Value (giá trị).
TStringList được khởi tạo như các class thông thường.
var
aList: TStringList;
begin
aList := TStringList.Create;
try
...
finally
aList.Free;
end;
end;
Như mọi class khác, bạn cần sử dụng cấu trúc try ... finally để tạo và giải phóng đối tượng khi sử dụng xong. Các lệnh thao tác với TStringList thì được đặt giữa try và finally (dấu ...)
Chúng ta sử dụng lại ví dụ về đối tượng aList đã tạo ở trên trong các thao tác bên dưới. Bạn có thể thay đổi lại cho phù hợp.
3.1. Truy xuất phần tử
Để truy xuất phần tử trong danh sách, bạn cần biết vị trí (index) của nó.
ShowMessage(aList[1]);
Đoạn trên xuất ra phần tử thứ 2 của list.
Lưu ý: TStringList đếm từ 0, nên index 1 có nghĩa là phần tử thứ hai. Khi truy xuất phần tử, cần chú ý đến phạm vi của nó. Nếu list chỉ có 2 phần tử mà bạn truy xuất đến phần tử thứ 3 (index = 2) thì sẽ bị lỗi.
Nâng cao: Delphi sử dụng thuộc tính TStringList.Strings để lưu trữ các string. Thế nên đoạn mã đầy đủ của aList[1] phải là aList.Strings[1]. Vì thuộc tính TStringList.Strings là mặc định (default) nên bạn có thể truy xuất nhanh như trên.
3.2. Lặp hết các phần tử
Sử dụng vòng lặp for ... to ... do hoặc for ... in để lặp hết các phần tử.
Dùng for ... to ... do
var
i: Integer;
begin
for i := 0 to aList.Count - 1 do
ShowMessage(aList[i]);
end;
Dùng for ... in
var
s: string;
begin
for s in aList.Strings do
ShowMessage(s);
end;
Tùy vào mục đích của bạn mà chọn cho phù hợp.
3.2. Tìm kiếm phần tử
Sử dụng method IndexOf để lấy vị trí của một string trong list.
var
s: string;
ViTri: Integer;
begin
s := 'ABC';
ViTri := aList.IndexOf(s);
if ViTri = -1 then
ShowMessage('List khong chua chuoi ABC')
else
ShowMessage('Chuoi ABC nam tai vi tri ' + ViTri.ToString);
end;
Đoạn mã trên tìm kiếm chuỗi ABC trong aList và thông báo vị trí, nếu không có thì in ra không chứa chuỗi ABC.
Nếu hàm IndexOf(chuỗi) trả về -1, nghĩa là không tìm thấy. Ngược lại sẽ là vị trí của string đó trong list.
3.3. Lấy toàn bộ list vào một string
Một tính năng khá hay và tiện trong Delphi là bạn có thể sử dụng TStringList như là một string duy nhất.
Thay vì phải lặp toàn bộ phần tử trong list và xuất ra (như ví dụ ở trên), bạn có thể sử dụng đoạn code sau.
ShowMessage(aList.Text);
Thuộc tính TStringList.Text sẽ thu gọn list thành một chuỗi duy nhất. Bạn có thể dùng ShowMessage để show nó ra, hoặc gán cho thuộc tính Text của một control khác, ví dụ như TLabel.
Label1.Caption := aList.Text;
Đoạn code trên sẽ hiển thị nội dung trong list lên một label trên form. Bình thường, label không thể hiển thị nhiều dòng được, nhưng trong trường hợp này thì có thể.
3.4. Thêm string vào list
Dùng method Add để thêm một string vào list (vào cuối list).
aList.Add('ABC');
aList.Add('123');
Bạn có thể truyền vào method Add chuỗi hoặc biến string đều được.
Một cái hay nữa là bạn có thể thêm nhiều dòng chỉ với một lần Add duy nhất. Sử dụng kí tự sLineBreak.
aList.Add(
'This is line 1' + sLineBreak +
'This is line 2' + sLineBreak +
'This is line 3'
);
3.5. Chèn string vào danh sách
Chèn vào list (Insert) cũng giống như thêm vào danh sách, nhưng có thêm một chỉ số index chỉ vị trí cần chèn vào, những phần tử khác sẽ bị đẩy ra phía sau.
aList.Insert(2, 'This is line 3');
Đoạn mã trên chèn string This is line 3 vào dòng thứ 3 của list (index là 2, nhưng vì đếm từ 0 nên là dòng thứ 3).
Lưu ý: Cần chú ý phạm vi chèn, không được chèn ra ngoài danh sách. Ví dụ nếu list chỉ có 3 phần tử mà chèn vào vị trí 5 sẽ bị lỗi.
3.6. Nối list vào list
Delphi cho phép bạn nối list này vào list khác. Sử dụng method AddStrings của lớp TStringList.
var
List1, List2: TStringList;
begin
List1 := TStringList.Create;
List2 := TStringList.Create;
try
...
List1.AddStrings(List2);
finally
List1.Free;
List2.Free;
end;
end;
Thao tác trên sẽ nối toàn bộ list2 vào list1.
3.7. Xóa toàn bộ list
Để xóa toàn bộ list (làm rỗng), sử dụng phương thức TStringList.Clear.
aList.Clear;
3.8. Di chuyển phần tử
Di chuyển phần tử có nghĩa là mang phần tử ở vị trí cũ (OldIndex) sang vị trí mới (NewIndex). Các phần tử nằm giữa hai vị trí này sẽ tự động di chuyển lên hoặc xuống cho phù hợp.
Giống như một hàng người đang xếp hàng. Nếu một người đi ra sau và chèn vào chỗ nào đó, thì những người khác nằm giữa hai vị trí sẽ tự động tiến lên 1.
Ngược lại, nếu có 1 người chen lên trước 3 vị trí thì những người nằm giữa sẽ bị đẩy xuống.
Tương tự với TStringList với method Move(OldIndex, NewIndex)
aList.Move(2, 0);
Code trên là chuyển phần tử thứ 3 (index = 2) lên vị trí đầu (index = 0). Các phần tử khác (nằm giữa 0 và 2) sẽ bị đẩy về sau 1 đơn vị.
Ví dụ đi cho dễ hiểu, một list có 5 phần tử.
0 1 2 3 4
A B C D E (Trước khi chạy)
C A B D E (Sau khi chạy)
Như trên, khi chạy code trên, C chuyển từ vị trí 3 (index 2) lên đầu (index 0). Thì khi đó, A và B bị đẩy về phía sau. Nhưng D và E không bị dịch chuyển.
3.9. Lưu / tải từ file
Bạn có thể lưu và nạp dữ liệu văn bản từ file sử dụng hai method LoadFromFile và SaveToFile (mà 2 method này được sử dụng không chỉ cho list mà còn dùng cho TImage dùng để tải hình ảnh và lưu ảnh).
LoadFromFile (tải từ file).
aList.LoadFromFile('C:\Users\ABC.txt');
SaveToFile (lưu vào file)
aList.SaveToFile('ABC.txt');
Nếu không có chỉ định đường dẫn tuyệt đối (có ổ đĩa và thư mục) thì mặc định lưu trong thư mục hiện tại.
Lưu ý: Khi sử dụng LoadFromFile, các dữ liệu đã có trong list sẽ bị xóa hết để chuẩn bị cho dữ liệu mới.
3.10. Sắp xếp (sort)
Sử dụng phương thức TStringList.Sort.
aList.Sort;
Mặc định, danh sách sẽ được sắp xếp theo thứ tự từ A đến Z. Để làm ngược lại, bạn có thể sử dụng vòng lặp for ... downto ... do để lặp từ cuối lên đầu list.
Một tính năng rất hay của TStringList là cho phép sử dụng dưới dạng từ điển. Cấu trúc từ điển gồm 2 phần: Key và Value. Biết Key, ta có thể tìm được value tương ứng.
Lấy ví dụ thực tế nhất là từ điển. Giả sử bạn có một file từ điển Anh - Việt như sau
One=Một
Two=Hai
Three=Ba
Four=Bốn
Như trên, các vế bên trái là Key, vế phải là Value. Từ điển đơn giản này có thể được lưu trong file, chẳng hạn tên là AnhViet.txt.
Dưới đây là một hàm, sử dụng TStringList dạng dictionary, nhận vào một string tiếng Anh và trả về tiếng Việt (dựa vào danh sách)
function ToVN(EN: string): string;
var
Dic: TStringList;
begin
Dic := TStringList.Create;
try
Dic.LoadFromFile('AnhViet.txt');
Dic.NameValueSeparator := '=';
Result := Dic.Values[EN];
finally
Dic.Free;
end;
end;
Thực ra list dạng dictionary chẳng có gì đặc biệt cả, bạn chỉ cần chú ý đến một số thuộc tính quan trọng sau:
NameValueSeparator: Kí tự phân cách, mặc định là dấu bằng (=). Nếu từ điển của bạn sử dụng kí tự khác, thì bạn phải đặt thuộc tính này đúng với giá trị đó. Nếu không thì list sẽ chỉ như TStringList bình thường thôi.
KeyName: Danh sách các key, nhận vào là index, trả về một key tại vị trí index.
Values: Truyền vào key, nhận lại là string. Ví dụ ở trên như Dic.Value('One') = Một
ValueFromIndex: Giống như values, nhưng thay vì truyền vào string thì truyền vào index. Ví dụ Dic.ValueFromIndex(0) = Một
Rồi, nói sơ về encoding. Encoding cơ bản là cách mã hóa các kí tự theo một quy chuẩn nào đó. Ví dụ, ANSI encoding thì mã hóa với 255 kí tự nên chỉ hiển thị những kí tự tiếng Anh thôi. UTF8 thì có thể mã hóa được nhiều hơn, khoảng 65536 kí tự nên có thể lưu được tiếng Việt. Unicode cũng tương tự như UTF8 nhưng tốn nhiều bộ nhớ hơn.
Tóm lại, có 3 encoding quan trọng:
UTF8: hiển thị đầy đủ bảng chữ cái của các ngôn ngữ khác nhau
Unicode: Tương tự UTF8 nhưng tốn nhiều bộ nhớ hơn
ANSI: Chỉ lưu được bảng chữ cái Latinh (ASCII)
Codepage là khái niệm gần giống như encoding, nhưng thiên về mã hóa file. File có chứa tiếng Việt thì nên được lưu dưới codepage là unicode hoặc UTF8.
Delphi sử dụng lớp TEncoding (lớp tĩnh) để lưu trữ các encoding.
TEncoding.UTF8;
TEncoding.Unicode;
Quay lại với TStringList, bạn có thể sử dụng encoding với TStringList thông qua thuộc tính DefaultEncoding và hai method có hỗ trợ encoding là LoadFromFile và SaveToFile.
var
aList: TStringList;
begin
aList := TStringList.Create;
try
aList.DefaultEncoding := TEncoding.Unicode;
aList.LoadFromFile('E:\File.txt', TEncoding.Unicode);
aList.SaveToFile('E:\FileNew.txt', TEncoding.UTF8);
finally
aList.Free;
end;
end;
Mặc định từ Delphi 7 trở đi, TStringList có encoding là UTF8. Bạn không cần thay đổi nếu không cần thiết. Ví dụ trên là đủ để các bạn nắm rõ được cách sử dụng encoding với TStringList.