Công cụ xử lý chuỗi
Null-terminated String và Strings Unit - những công cụ xử lý chuỗi hiệu quả của PascalNgô Minh Đức- Null-terminated Strings là kiểu chuỗi có giới hạn lên tới 65535 ký tự, các hàm xử lý trên kiểu chuỗi này từ lâu đã được Pascal cung cấp trong Strings Unit và được hướng dẫn sử dụng trong phần help của Pascal. - Null-terminated Strings được khai báo bằng một mảng ký tự: array[0 X] of char trong đó X là một số nguyên dương đạt giá trị tối đa là 65534 - Strings Unit: của Pascal cung cấp các hàm xử lý trên Null-terminated Strings. Để sử dụng được Strings Unit ta phải đặt compiler directive {$X} ở chể độ + (mặc định). - Kiểu PChar: là một kiểu dữ liệu đặc biệt, dùng để xử lý các Null-terminated Strings. Thực ra PChar là một kiểu con trỏ được khai báo như sau: type PChar=^Char nhưng PChar được trang bị một số phép toán đặc biệt Chúng ta có thể dùng PChar giống kiểu String: Var P:PChar; . P:='ISM'; {hợp lệ} Write(P); {in ra chữ 'ISM'} Write(P[0]) {in ra chữ 'I'} Write(P[2]) {in ra chữ 'M'} Tuy nhiên chúng ta có thể sử dụng theo cách khác: Write(P^); {in ra chữ 'I' } Write((P+1)^); {in ra chữ 'S'} Write(P+1); {in ra chữ 'SM' } Tóm lại: khi bạn khai báo P:='ISM' có nghĩa là con trỏ P đã được chỉ vào chữ 'I', chữ đầu của chuỗi 'ISM'. Vì vậy P^ mang giá trị 'I'. Cách viết P+1 chính là sự đặc biệt của kiểu PChar, P+1 chính là con trỏ trỏ vào chữ 'S'. Ngoài ra còn chúng ta thấy cách viết Write(P) trong đó P mang kiểu PChar là hoàn toàn hợp lệ, nó in ra chuỗi mà con trỏ P đang trỏ vào ký tự đầu tiên. Khi ta viết Write(P) thì được 'ISM' còn viết Write(P+1) thì được 'SM'. - Kiểu PChar được trang bị các phép tính sau: Với P, Q kiểu PChar, I kiểu Word thì: P + I: trỏ vào ký tự đứng sau ký tự mà P trỏ vào I ký tự P - I: trỏ vào ký tự đứng trước ký tự mà P trỏ vào I ký tự P - Q: nếu P và Q trỏ vào hai ký tự của cùng một chuỗi, kết qủa sẽ là khoảng cách giữa hai ký tự đó. Ví dụ trong chuỗi 'ISM', P trỏ vào chữ 'M', Q trỏ vào chữ 'I' thì P-Q=2 Nếu P và Q trỏ vào hai chuỗi khác nhau, kết qủa vô nghĩa. - Phép gán mảng ký tự dạng Null-Terminated Strings (Array[0 X] Of Char) cho kiểu PChar là hợp lệ. Ví dụ: Const Number:Array[0 4] Of Char = ('1','2','3','4','5'); Var P:Pchar; . P:=Number; {hợp lệ} Write(P); {in ra '12345'} - Xét một hàm dạng như sau của Strings Unit: Function StrCopy(Dest, Source: PChar): PChar; Khi đó bạn có thể dùng kiểu mảng Null-terminated Strings hoặc kiểu PChar cho các tham số. Bạn có thể viết StrCopy(P, 'ISM'); vì 'ISM' sẽ được hiểu là kiểu PChar chứ không phải là kiểu String của Pascal - Khi sử dụng các hàm của Strings Unit, chẳng hạn: Var P:PChar; . StrCopy(P,'Turbó); Thì khi viết Write(P) sẽ không hiện ra chữ 'Turbó mặc dù khi viết Write(P^) vẫn in ra chữ 'T' và Write(P+1) vẫn in ra chữ 'urbó - Với kiểu PChar thì không thể đọc được dữ liệu: Var P:PChar; F:Text; . Readln(P) hoặc Readln(F,P); {không hợp lệ} nhưng với kiểu mảng Null-terminated Strings (tức là bắt buộc phải có dạng Array[0 X] of Char) thì đọc được dữ liệu: var S:array[0 1000] Of Char; F:Text; . Readln(S); hoặc Readln(F,S); {hợp lệ} - Vì vậy ta thường không khai báo kiểu PChar mà khai báo kiểu mảng Null-terminated Strings: Var S: array[0 1000] Of Char; . StrCopy(S, 'Turbó); Đặc biệt trong kiểu mảng Null-terminated Strings thì cách viết Write(S+1) vẫn hợp lệ (in ra chữ 'urbó) - Ta không dùng các hàm của Strings Unit như một Function mà hay dùng như Procedure (hợp lệ nhờ khai báo $X+), như sau: Var S:Array[0 100] Of Char; . Strcopy(S,'Turbó); Ta viết: StrCat(S,'Pascal') chứ không viết S:=StrCat(S,'Pascal'); {không hợp lệ} Write(S); {in ra 'Turbo Pascal'} Các hàm của Strings Unit: - StrCat: Nối 2 chuỗi function StrCat(Dest, Source: PChar): PChar; vd: . StrCopy(S,'Turbó); StrCat(S,'Pascal'); Write(S); {in ra 'Turbo Pascal'} - StrLCat: Nối một số kí tự của chuỗi này vào chuỗi kia function StrLCat(Dest, Source:PChar; MaxLen:Word):Pchar; copy MaxLen-StrLen(Dest) ký tự từ chuỗi Source vào chuỗi Dest vd: . StrCopy(S,'Turbó); StrLCat(S,'Pascal',7); Write(S); {in ra 'Turbo P'} - StrComp: so sánh hai chuỗi function StrComp(Str1,Str2:PChar):Integer; Tương tự cách so sánh <, =, >, <=, > của kiểu String thường Trả về kết qủa: < 0 ne^'u Str1=0 nếu Str1=Str2 >0 nếu Str1>Str2 Phân biệt chữ thường và chữ hoa. Vd: StrComp('A','A')=0 nhưng StrComp('á,'A')=32 - StrIComp: giống StrComp nhưng không phân biệt chữ thường và chữ hoa - StrLComp: so sánh một số ký tự của hai chuỗi function StrLComp(Str1,Str2:PChar; MaxLen:Word):Integer; vd: StrLComp(S1,S2,5); {so sánh 5 kí tự đầu của hai chuỗi S1, S2} - StrLIComp: giống StrLComp nhưng không phân biệt chữ thường và chữ hoa - StrCopy: copy một chuỗi vào chuỗi khác function StrCopy(Dest, Source:PChar):PChar; vd: . StrCopy(S,'Turbo Pascal'); Write(S); {In ra 'Turbo Pascal'} - StrECopy: copy một chuỗi vào chuỗi khác và trả về con trỏ trỏ tới vị trí cuối cùng của chuỗi kết qủa funtion StrECopy(Dest, Source:PChar):PChar; vd: var P:PChar; S:Array[0 1000] Of Char; P:=StrECopy(S,'Turbó); Write(P-5); {in ra 'Turbó); hoặc var S:Array[0 1000] Of Char; StrECopy(StrECopy(StrECopy(S,'Turbó), ' '), 'Pascal'); Write(S); {in ra 'Turbo Pascal'} - StrLCopy: copy các ký tự của một chuỗi vào chuỗi khác function StrLCopy(dest, Source: PChar; MaxLen:Word):PChar; vd: write(StrCopy(S,'Turbo Pascal', 5)); {in ra 'Turbó} - StrEnd: trả về con trỏ trỏ tới vị trí cuối cùng của chuỗi function StrEnd(str:PChar):PChar; - StrNew: Cấp vùng nhớ cho một chuỗi mới trên heap function StrNew(Str:PChar):PChar; vd: var P:PChar; . StrCopy(S,'TurboPascal'); P:=StrNew(S); Lúc này P là con trỏ PChar ứng với chuỗi mới 'Turbo Pascal' vừa được tạo ra (bây giờ 2 chuỗi S và P độc lập nhau nhưng đều có giá trị 'Turbo Pascal') - StrDispose: Thu hồi lại vùng nhớ của chuỗi vừa được cấp bởi StrNew function StrDispose(Str:PChar); vd: P:=StrNew(S); StrDispose(P); {lúc này P=Nil} - StrLen: trả về độ dài chuỗi function StrLen(Str:PChar):Word; - StrLower: đổi chuỗi thành toàn chữ thường function StrLower(Str:PChar):PChar; vd: StrCopy(S,'TuRbó); StrLower(S); Write(S); {in ra 'turbó} - StrUpper: đổi chuỗi thành toàn chữ hoa function StrUpper(Str:PChar):PChar; - StrMove: copy một số kí tự từ chuỗi này sang chuỗi khác function StrMove(Dest, Source: PChar; Count: Word): Pchar; thay thế (count) kí tự đầu của chuỗi Dest bằng (count) kí tự đầu của chuỗi Source vd: Write(strMove('Purbó,'Tablé,1)); {in ra 'Turbó} - StrPas: đổi null-terminated string thành Pascal string function StrPas(str:PChar):String; - StrPCopy: đổi Pascal String thành null-terminated String function StrPCopy(dest:Pchar; Source: String):Pchar; - StrPos: function StrPos(Str1, Str2:PChar):PChar; Trả về con trỏ trỏ đến vị trí xuất hiện đầu tiên của chuỗi Str2 trong chuỗi Str1, nếu chuỗi Str2 không xuất hiện trong chuỗi Str1, trả về Nil - StrScan: function StrScan(Str:Pchar; Chr:Char):PChar; Trả về con trỏ trỏ đến vị trí xuất hiện đầu tiên của kí tự Chr trong chuỗi Str, nếu kí tự Chr không xuất hiện trong chuỗi Str, trả về Nil - StrRScan : function StrRScan(Str:Pchar; Chr:Char): PChar; Trả về con trỏ trỏ đến vị trí xuất hiện cuối cùng của kí tự Chr trong chuỗi Str, nếu kí tự Chr không xuất hiện trong chuỗi Str, trả về Nil Bài toán áp dụng Cho một file văn bản text.inp gồm nhiều dòng, mỗi dòng không quá 255 kí tự. Một cụm từ S không qúa 255 kí tự. Hãy tìm số lần xuất hiện của cụm từ S trong văn bản. Ta có thể nghĩ đến giải pháp đọc từng dòng của văn bản, sau đó dùng hàm Pos của Pascal để tìm chuỗi S trong dòng đó. Nhưng khi đó xảy ra trường hợp cụm từ S có thể nằm trên hai dòng: Chẳng hạn: S='Tin học và nhà trường' Và văn bản là: Tin học và nhà trường Vì vậy chúng ta phải nghĩ tới cách khác. Chúng ta có thể tách S thành từng từ để tìm, nhưng sao chúng ta không thử dùng null-terminated strings? Sau đây tôi thử cài đặt chương trình dùng null-terminated string: Giải pháp đưa ra là: tạo một chuỗi null-terminated string: var str:array[0 1000] Of Char; Mỗi lần ta đọc vào chuỗi str một số dòng của văn bản sao cho không lớn hơn sức chứa của str, sau đó sử dụng hàm StrPos để tìm chuỗi S trong str Sau đó gọi lệnh: StrCopy(Str,StrEnd(Str)-StrLen(S)+1); Tiếp tục đọc các dòng văn bản vào Str và lặp lại việc tìm kiếm. + Dữ liệu: file text.inp dòng đầu tiên chứa cụm từ S các dòng tiếp theo chứa nội dung của văn bản + Kết qủa: file text.out gồm một dòng duy nhất chứa số tự nhiên N là số lần xuất hiện của cụm từ S trong văn bản Chương trình như sau: Uses Strings; Const fInput='text.inp'; fOutput='text.out'; maxLen=1000; lineLen=255; Var Str:Array[0 maxLen] Of Char; S:Array[0 lineLen] Of Char; N:Longint; Procedure Search; Var P:PChar; Begin P:=StrPos(Str,S); While P<>Nil Do Begin N:=N+1; P:=StrPos(P+1,S); End; StrCopy(Str,StrEnd(Str)-StrLen(S)+1); End; Procedure Xuly; Var F:Text; sLine:array[0 lineLen] Of Char; Begin Assign(F,fInput); Reset(F); Readln(F,S); n:=0; While Not Eof(F) Do Begin Readln(F,sLine); If (StrLen(Str)+StrLen(sLine))>=maxLen Then Search; StrCat(Str,sLine); StrCat(Str,' '); End; Search; Close(F); End; Procedure Xuat; Var F:Text; Begin Assign(F,fOutput); Rewrite(F); Write(F,N); Close(F); End; Begin Xuly; Xuat; End. . những công cụ xử lý chuỗi hiệu quả của PascalNgô Minh Đức- Null-terminated Strings là kiểu chuỗi có giới hạn lên tới 65535 ký tự, các hàm xử lý trên kiểu chuỗi. kí tự của chuỗi này vào chuỗi kia function StrLCat(Dest, Source:PChar; MaxLen:Word):Pchar; copy MaxLen-StrLen(Dest) ký tự từ chuỗi Source vào chuỗi Dest