II/ KIỂU MẢNG, KIỂU CHUỖI
2. Dữ liệu kiểu chuỗi (String Type Data)
Một chuỗi dữ liệu là một loạt các ký tự được định nghĩa bằng từ khoá STRING theo sau là số ký tự cực đại có thể có của chuỗi ký tự. String là một kiểu cấu trúc được thêm vào trong Turbo Pascal.
a) Khai báo
Chúng ta có thể khai báo kiểu chuỗi ký tự String gián tiếp hoặc trực tiếp. Khai báo gián tiếp là khai kiểu trước rồi sau đó mới khai báo biến. Cách khai báo trực tiếp là khai thẳng biến số. Chiều dài tối đa của chuỗi ký tự phải là một hằng nguyên và được đặt trong dấu ngoặc vuông [ ]. Trường hợp không khai báo thì chương trình sẽ lấy giá trị mặc nhiên là 255 ký tự
+ Khai báo gián tiếp
TYPE
<Tên kiểu String> = STRING [hằng nguyên] ; VAR
<Tên biến> : <Tên kiểu String> ; Ví dụ 2.7:
TYPE
TenSV = STRING [25] ; {định độ dài tối đa là 25} Diachi = STRING; {mặc nhiên có độ dài tối đa là 255} VAR
HT : TenSV ; DC : Diachi ;
VAR
<Tên biến> : STRING [hằng nguyên] ;
Ví dụ 2.8:
VAR
HT : STRING [25] ; DC : STRING;
Chuỗi ký tự sẽ chiếm số byte trong bộ nhớ bằng số ký tự lớn nhất đã khai báo trước
cộng thêm 1 byte đầu tiên chứa số ký tự hiện có của chuỗi ký tự.
Ví dụ 2.9:
TYPE DH = STRING[10] ; VAR CT : DH ;
và nếu ta gán CT := CAN THO;
thì CT sẽ được cấp phát 1 + 10 = 11 ô nhớ (byte) liên tục, với hình ảnh sau :
Chú ý:
- Ðộ dài của chuỗi ký tự CT là 7 ký tự mặc dầu độ dài lớn nhất cho phép là 10. - Vì ta dùng 1 byte để chứa chiều dài nên string chỉ có tối đa là 255 ký tự.
b) Các thao tác trên chuỗi
+ Phép gán
Giống như phép gán trong các kiểu vô hướng khác, phép gán chuỗi là lệnh gắn một biến với một biểu thức ký tự để trong cặp dấu nháy đơn
Cú pháp:
<Tên biến> := Biểu thức ký tự ;
Ví dụ 2.8:
HT := Lê Văn Hai ;
DC := Số 12/4 đường Trần Hưng Ðạo, TP. Cần thơ ;
Phép cộng là thuật toán nối các chuỗi lại với nhau bằng dấu cộng (+). Ví dụ trên nếu ghép HT + DC thì ta sẽ được:
Lê Văn Hai Số 12/4 đường Trần Hưng Ðạo, TP. Cần thơ Ghi chú: Không có phép trừ, nhân, chia trong chuỗi ký tự.
+ Các phép so sánh
Các so sánh gồm có bằng nhau =, lớn hơn >, lớn hơn hoặc bằng >=, khác nhau <>, nhỏ hơn <, nhỏ hơn hoặc bằng <=
Khi so sánh 2 chuỗi ký tự thì các ký tự được so sánh từng cặp một từ trái sang phải theo giá trị của bảng mã ASCII. Có 2 khả năng xảy ra khi so sánh:
- Nếu 2 chuỗi có độ dài khác nhau nhưng số ký tự giống nhau cho đến độ dài chuỗi ngắn nhất thì chuỗi ngắn nhỏ hơn chuỗi dài.
Ví dụ 2.9: 'Nation' < 'National ''Lan' < 'Lang' - Nếu 2 chuỗi có độ dài và nội dung giống nhau thì bằng nhau.
Ví dụ 2.10: 'Hello' = 'Hello'
Ghi chú: Chuỗi rổng (null string, viết là '') là chuỗi không có chứa gì cả. Nó có giá trị nhỏ hơn mọi string khác rỗng.
Vì vậy: 'A' >'' và chr(32)> ''
+ Câu lệnh Read và Readln
Hai câu lệnh này đối với chuỗi cũng tương tự như đối với các kiểu vô hướng khác, nhưng cần lưu ý:
- Lệnh Read và Readln chỉ cho phép đọc tối đa 127 ký tự một chuỗi nhập từ bàn phím mặc dầu chiều dài tối đa của một chuỗi có thể đến 255 ký tự.
- Nếu ta đọc một lúc nhiều biến theo kiểu Read(biến1, biến2, ..., biếnN) ( hoặc Readln(biến1, biến2, ..., biếnN)) thì có thể bị nhầm lẫn khi ta nhập giá trị có độ dài vượt quá độ dài tối đa của biến1 thì phần vượt sẽ được gán cho biến2. Ngược lại, nếu ta nhập giá trị ít hơn độ dài của biến1 thì chương trình lại lấy các giá trị của biến2 gán thêm cho biến1 kể cả khoảng trống. Do vậy, cách tốt nhất là đối với biến kiểu String chỉ nên nhập mỗi lần 1 biến.
Ví dụ 2.11: Nên tránh viết kiểu Read(TenSV, Diachi); mà nên viết : Read(TenSV) ;
Read(Diachi) ; hoặc:
Readln(Diachi) ;
- Ðộ dài thực tế của chuỗi là độ dài thực tế khi ta đọc vào từ bàn phím mặc dầu trước đó ta có khai báo độ dài chuỗi. Nếu ta gõ Enter mà không gõ ký tự nào trước đó thì mặc nhiên chương trình hiểu đó là một chuỗi rỗng (null string hay st = '').
+ Câu lệnh Write và Writeln
Tương tự như trên nhưng cần một số lưu ý về cách viết:
- Nếu viết Write(st) hoặc Writeln(st) gọi là cách viết không qui cách thì mỗi ký tự sẽ chiếm 1 vị trí trên màn hình.
- Nếu viết Write(st : n) hoặc Writeln(st : n) gọi là cách viết theo qui cách, với n là số nguyên, thì màn hình sẽ dành n vị trí để viết chuỗi st theo lối canh trái nếu n> 0 và ngược lại theo lối canh phải nếu n < 0.
- Một số chuỗi mà trong đó có dấu như là một chữ viết tắt, ví dụ như câu: Hes an Intal staff (Ông ta là một nhân viên quốc tế) thì nơi có dấu phải viết thành (đây là 2 dấu nháy đơn chứ không phải là 1 dấu nháy kép ).
Ta viết:
Writeln ( ‘ He ‘’s an Int’’al staff ‘) ;
c) Các thủ tục và hàm chuẩn xử lý chuỗi ký tự
Chuỗi ký tự được dùng khá phổ biến trong lập trình nên Turbo Pascal đã đưa sẵn vào một số thủ tục và hàm chuẩn để xử lý chuỗi ký tự.
* Thủ tục xóa DELETE (St, Pos, Num)
Ý nghĩa: Xóa khỏi chuỗi St một số ký tự là Num bắt đầu từ vị trí Pos tính từ trái sang.
Ví dụ 2.12: VAR st : string [20]; BEGIN
St := ' BÀ BA BÁN BÁNH BÒ '; Writeln (St) ; DELETE (St, 10, 4); Writeln(St); Readln ; END.
Khi chạy chương trình, ta sẽ thấy trên màn hình: BÀ BA BÁN BÁNH BÒ
BÀ BA BÁN BÒ
* Thủ tục INSERT (Obj, St, Pos)
Ý nghĩa: Chèn chuỗi Obj xen vào chuỗi St kể từ vị trí Pos tính từ bên trái.
Ví dụ 2.13: VAR st : string [25]; BEGIN
INSERT ( BỤNG BỰ , St, 6); Writeln(St); Readln ; END.
Khi chạy chương trình, ta sẽ thấy trên màn hình: BÀ BA BÁN BÁNH BÒ
BÀ BA BỤNG BỰ BÁN BÁNH BÒ
* Thủ tục STR (S [: n[: m]], St)
Ý nghĩa: Ðổi giá trị số S thành chuỗi rồi gán cho St, Giá trị n:m nếu có sẽ là số vị trí và số chữ số thập phân của S. Ví dụ 2.14: VAR S: real; St: string[10]; BEGIN S:= 12345.6718; Writeln(S:5:2); Str(S:6:2:st); Readln; END. Kết quả trên màn hình: 12345.67 {Ðây là số } 12345.67 {Ðây là chuỗi} * Thủ tục VAL(St, S, Code)
Ý nghĩa: Ðổi chuỗi số St (biểu thị một số nguyên hoặc số thực) thành số (số nguyên hoặc số thực) và gán giá trị này cho S. Code là số nguyên dùng để phát hiện lỗi: nếu đổi đúng thì Code có giá trị = 0, nếu sai do St không biểu diễn đúng số nguyên hoặc số thực thì Code sẽ nhận giá trị bằng vị trí của ký tự sai trong chuỗi St. Ví dụ 2.15: VAR St : String[10]; SoX : real; maloi: integer; BEGIN St:= ‘123.456’ ; VAL(St,SoX,maloi) ;
Writeln('Số X = , SoX :5:2, và mã lỗi = , maloi) ; Readln;
VAL(St,SoX,maloi);
Writeln('St = 123.XXX không đổi thành số được !'); Writeln('Sai lỗi ở vị trí thứ ' , maloi); Readln;
END.
Khi chạy, ta sẽ thấy trên màn hình: 123.45 và maloi = 0
St = 123.XXX không đổi thành số được ! Sai lỗi ở vị trí thứ 5
* Hàm LENGTH (St)
Ý nghĩa: Cho kết quả là một số nguyên chỉ độ dài của chuỗi ký tự St.
Ðể viết 1 chuỗi ký tự ở trung tâm màn hình, ta có thể dùng thủ thuật viết chuỗi là (80 - lenght(st)) div 2
Ví dụ 2.16: USES CRT;
VAR St : String[80]; BEGIN
ClrScr ;
Write(' Nhập vào một câu : '); Readln(St) ; Gotoxy(80 - Lenght(St)) div2, 12);
Writeln(St) ; Readln ; END.
* Hàm COPY (St, Pos, Num)
Ý nghĩa: Cho kết quả là một chuỗi ký tự mới có được bằng cách chép từ chuỗi St, bắt đầu từ vị trí Pos và chép Num ký tự.
Nếu vị trí Pos lớn hơn chiều dài của chuỗi St thì hàm COPY sẽ cho một chuỗi rỗng. Nếu giá trị của vị trí Pos và số ký tự Num (Pos + Num) lớn hơn chiều dài của chuỗi St thì hàm COPY chỉ nhận các ký tự nằm trong chuỗi St.
Ví dụ 2.17: VAR St1, St2 : string[25] ; BEGIN St1 := ‘UNIVERSITY OF CANTHO : 1966 - 1996’ ; St2 := COPY (St1, 15, 6) ; END.
* Hàm CONCAT (St1, St2, ..., StN)
Ý nghĩa: Cho kết quả là một chuỗi mới được ghép theo thứ tự từ các chuỗi St1, St2, ..., StN. Hàm này giống như phép cộng các chuỗi. Chuỗi mới cũng sẽ không được vượt quá 255 ký tự.
* Hàm POS (Obj, St) :
Ý nghĩa: Cho kết quả là vị trí đầu tiên của chuỗi Obj trong chuỗi St. Nếu không tìm thấy thì hàm POS cho giá trị 0.
Ví dụ 8.27:
nếu St := 1234567890, nếu Obj := 456 thì POS (Obj, St) = 4 còn POS(4X, St)=0