Từ khi máy vi tính trở nên phổ biến và rộng rãi trong nước, nhu cầu sử dụng chữ Việt trên máy vi tính đã trở thành nhu cầu cấp thiết đối với người sử dụng. Việc đưa tiếng Việt vào máy tính là một vấn đề có tầm quan trọng trong việc tin học hóa, phổ cập tin học và phát triển công nghệ phần mềm trong nước. Do vậy đã có nhiều cá nhân, tập thể trong và ngoài nước đã tập trung nhiều công sức trong việc đưa tiếng Việt vào các máy tính nói chung và máy vi tính nói riêng.
Hiện nay có rất nhiều phần mềm đưa tiếng Việt vào máy tính, số lượng các phần mềm này lớn cho ta thấy được ý nghĩa của việc đưa tiếng Việt vào máy tính. Tuy nhiên mỗi phần mềm này lại có một cách thức thể hiện khác nhau (cách mã hóa ký tự tiếng Việt khác nhau). Có rất nhiều cách mã hóa ký tự Tiếng Việt. Mặc dù khác nhau, không thống nhất theo những quy tắc chung, các giải pháp tiếng Việt đã phần nào đáp ứng được nhu cầu thực tiễn, ít nhất cũng trong phạm vi của một tổ chức, cơ quan.và góp phần vào việc “Việt hóa” các ứng dụng cho máy tính.
Ở cấp độ các cơ quan nhà nước, một bộ mã tiếng Việt duy nhất được thống nhất sử dụng, đó là bộ mã TCVN3 hay còn gọi là mã ABC. Mặc dù vẫn còn nhiều khiếm khuyết nhưng trên thực tế, bộ mã tiếng Việt 8 bit này đã được chấp nhận và lưu hành rộng rãi tại Hà Nội và các tỉnh phía Bắc sau một số năm áp dụng. Việc xử lý các văn bản sử dụng bảng mã ABC vẫn có ý nghĩa quan trọng trong thời điểm hiện tại.
33 trang |
Chia sẻ: oanh_nt | Lượt xem: 990 | Lượt tải: 0
Bạn đang xem trước 20 trang nội dung tài liệu Chuyên đề Xây dựng chương trình thống kê kí tự đơn và kí tự đôi trong file văn bản tiếng Việt mã ABC, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
I. Đặt vấn đề
*Mục đích của đề tài
Từ khi máy vi tính trở nên phổ biến và rộng rãi trong nước, nhu cầu sử dụng chữ Việt trên máy vi tính đã trở thành nhu cầu cấp thiết đối với người sử dụng. Việc đưa tiếng Việt vào máy tính là một vấn đề có tầm quan trọng trong việc tin học hóa, phổ cập tin học và phát triển công nghệ phần mềm trong nước. Do vậy đã có nhiều cá nhân, tập thể trong và ngoài nước đã tập trung nhiều công sức trong việc đưa tiếng Việt vào các máy tính nói chung và máy vi tính nói riêng.
Hiện nay có rất nhiều phần mềm đưa tiếng Việt vào máy tính, số lượng các phần mềm này lớn cho ta thấy được ý nghĩa của việc đưa tiếng Việt vào máy tính. Tuy nhiên mỗi phần mềm này lại có một cách thức thể hiện khác nhau (cách mã hóa ký tự tiếng Việt khác nhau). Có rất nhiều cách mã hóa ký tự Tiếng Việt. Mặc dù khác nhau, không thống nhất theo những quy tắc chung, các giải pháp tiếng Việt đã phần nào đáp ứng được nhu cầu thực tiễn, ít nhất cũng trong phạm vi của một tổ chức, cơ quan...và góp phần vào việc “Việt hóa” các ứng dụng cho máy tính.
ở cấp độ các cơ quan nhà nước, một bộ mã tiếng Việt duy nhất được thống nhất sử dụng, đó là bộ mã TCVN3 hay còn gọi là mã ABC. Mặc dù vẫn còn nhiều khiếm khuyết nhưng trên thực tế, bộ mã tiếng Việt 8 bit này đã được chấp nhận và lưu hành rộng rãi tại Hà Nội và các tỉnh phía Bắc sau một số năm áp dụng. Việc xử lý các văn bản sử dụng bảng mã ABC vẫn có ý nghĩa quan trọng trong thời điểm hiện tại.
*Giói thiệu bài toán cụ thể của đề tài
Chuyên đề thực tập này có nội dung như sau:
“Xây dựng chương trình thống kê kí tự đơn và kí tự đôi trong file văn bản tiếng Việt mã ABC”.
Đề tài gồm hai phần:
Phần thứ nhất thống kê tất cả các kí tự đơn của file văn bản
Phần thứ hai liệt kê số lần xuất hiện của một kí tự đơn sau một kí tự đơn khác là bao nhiêu lần trong toàn bộ file văn bản (ví dụ ta có kí tự đôi “ca”, vậy kí tự “a” sẽ đứng sau kí tự “c” là bao nhiêu lần trong văn bản), sau đó tính tần suất xuất hiện kí tự đôi.
II. Cơ sở lý thuyết của đề tài thực tập
Trình bầy tổng quan các nghiên cứu trong lý thuyết
1) File văn bản
Để giải bài toán đặt ra, trước hết ta phải xác định kiểu file đầu vào cho chương trình. Trong Turbo Pascal, file văn bản được hiểu theo nghĩa chuẩn, các dữ liệu được lưu trữ dưới dạng các ký tự trong bảng mã ASCII. Các ký tự được liên kết thành từng dòng, dấu hết dòng được ghi nhận bởi cặp ký tự điều khiển có mã 13 (ký tự trở về đầu dòng - CR) và ký tự có mã 10 (ký tự xuống dòng - Lf). Không có quy định về chiều dài dòng cho file văn bản.
Turbo Pascal dùng tên chuẩn Text để đặt cho file văn bản. Vì thế lời khai báo biến file văn bản sẽ là:
Var
f: text;
File văn bản chỉ có thể truy cập tuần tự chứ không thể truy cập trực tiếp như file định kiểu. Và cũng không thể vừa đọc vừa ghi trên file văn bản như file định kiểu.
Tuy nhiên vì file văn bản không phụ thuộc vào định nghĩa kiểu thành phần nên nó là công cụ giao tiếp chung giữa các chương trình. Bất cứ chương trình nào cũng có thể đọc dữ liệu từ file văn bản và kết xuất dữ liệu dưới dạng văn bản. Việc soạn thảo file văn bản có thể dùng bất cứ một hệ soạn thảo nào (là những chương trình tiện ích vốn rất phong phú hiện nay). Chẳng hạn, có thể dùng ngay hệ soạn thảo của chính Turbo Pascal để xây dựng và hiệu chỉnh file văn bản.
Các bước thao tác trên file văn bản tuân theo quy trình như sau: đầu tiên cần đăng ký biến file văn bản (f) với tên file trên đĩa (name) bằng thủ tục Assign (f, name). Sau đó mở file bằng thủ tục Reset (f) nếu nó đã có để chuẩn bị đọc, hoặc mở bằng thủ tục Rewrite (f) nếu muốn tạo mới để chuẩn bị ghi. Sau Reset chỉ có thể đọc và sau Rewrite chỉ có thể ghi. Mỗi lần đọc ghi xong con trỏ lại định vị đến vị trí kế tiếp. Việc đọc dữ liệu từ file văn bản tương tự như đọc từ bàn phím, cũng dùng các thủ tục Read (f, var1, var2, ...), Readln nếu muốn đọc từng dòng. Các biến ký tự được đọc theo từng đơn vị ký tự, các biến xâu ký tự được đọc đúng độ dài của nó hoặc cho đến khi gặp dấu xuống dòng. Việc ghi ra file văn bản cũng tương tự như ghi ra màn hình (cũng dùng các thủ tục write và writeln). Sau khi thao tác xong cần đóng file nhờ thủ tục Close (f) để đảm bảo an toàn dữ liệu.
Ngoài ra còn có thủ tục Append (f) để mở một văn bản có sẵn để ghi kế tiếp, hàm Eof (f) để kiểm tra đã định vị đến cuối file chưa...
2) Kiểu con trỏ
Trong Pascal, kiểu con trỏ là một kiểu dữ liệu đặc biệt, dùng để biểu diễn những giá trị địa chỉ. Như thế kiểu con trỏ là những biến dùng để lưu những giá trị địa chỉ của bộ nhớ. Nhờ các biến con trỏ, ta có thể thao tác trên các giá trị địa chỉ cũng như truy cập dữ liệu ở các vùng nhớ một cách linh hoạt. Ngoài ra, biến con trỏ còn là công cụ để xin cấp phát trên vùng Heap (cấp phát động) và xây dựng kiểu dữ liệu động, cho phép chương trình có thể khai thác tối đa và hiệu quả bộ nhớ.
Có hai kiểu con trỏ là con trỏ định kiểu và con trỏ không định kiểu.
Với bài toán đã cho, con trỏ định kiểu được sử dụng. Con trỏ định kiểu cần xác định kiểu dữ kiệu mà nó trỏ đến. Turbo Pascal dùng ký hiệu ^ trước tên kiểu dữ liệu để khai báo con trỏ định kiểu:
Type
PtrType = ^DataType;
trong đó: PtrType là tên kiểu con trỏ
DataType là tên kiểu dữ liệu xác định kiểu dữ liệu được trỏ.
Vì kiểu con trỏ chỉ lưu địa chỉ nên nó có thể khai báo trước kiểu dữ liệu được trỏ. Chẳng hạn, có quyền khai báo:
PtrType = ^ DataType;
DataType = record
..............
end;
Hai biến con trỏ có thể gán giá trị cho nhau trong các trường hợp tương thích. Khi đó chúng cùng trỏ tới một địa chỉ. tuy nhiên, hai con trỏ định kiểu mà trỏ tới các kiểu dữ liệu khác nhau là không tương thích.
Để truy cập dữ liệu mà con trỏ p đang trỏ, Turbo Pascal dùng ký hiệu p^. Ký hiệu này đóng vai trò như một biến, có nội dung là nội dung vùng dữ liệu mà p đang trỏ. Dùng p^ có thể thay cho các mảng Mem và các biến tuyệt đối trong việc truy cập bộ nhớ.
Khi p là con trỏ định kiểu. Khi đó p^ là biến định kiểu có địa chỉ đựợc p lưu giữ. Kiểu của p^ được xác định là kiểu mà con trỏ p trỏ tới. Mọi thao tác trên biến dịnh kiểu thông thường đều được áp dụng cho p^. Tuy nhiên, p^ là một biến định kiểu đặc biệt, nó có thể thay đổi địa chỉ trong quá trình hoạt động bằng cách gán địa chỉ tương ứng cho p, vì thế p^ có thể truy cập vào bất cứ vùng nhớ nào theo kiểu dữ liệu của nó. Có thể xem p^ như một biến tuyệt đối có khả năng thay đổi địa chỉ nhờ phép gán.
3) Cấp phát động
Việc dùng p^ bằng cách gán cho p một giá trị địa chỉ không phải là việc cung cấp một biến p^ mới, vì thế phải hết sức thận trọng khi truy cập p^. Muốn p^ thực sự được cấp phát như một biến, phải dùng kỹ thuật cấp phát động cho p. Cấp phát động được thực hiện bằng câu lệnh trong thân chương trình (chứ không phải bằng khai báo) và được thu hồi nếu cần (cũng bằng câu lệnh trong chương trình). Vùng cấp phát động bao giờ cũng là vùng nhớ tự do (Heap). Địa chỉ vùng cấp phát động được quản lý bởi các biến con trỏ. Việc cấp phát động cho phép người lập trình sử dụng bộ nhớ linh hoạt và tiết kiệm đặc biệt, nhờ cấp phát động, người ta có thể xây dựng được những kiểu dữ liệu động, cho phép khai thác tối đa bộ nhớ.
Cấp phát động là một ứng dụng quan trọng của con trỏ. Việc dùng con trỏ thường được gắn liền với cấp phát động. Nhứng biến được xin trong vùng Heap nhờ cấp phát động, được gọi là những biến động (dynamic variable) để phân biệt với những biến thông thường được xin từ khai báo.
Pascal tổ chức hai cách cấp phát động: Một, dành cho các con trỏ định kiểu và hai, dành cho con trỏ bất kỳ (không quan tâm đến kiểu). ở đây chúng ta chỉ quan tâm đến cấp phát cho con trỏ định kiểu - được gọi là cấp phát định kiểu.
Giả sử p là một con trỏ định kiểu. thủ tục New (p) sẽ cấp một vùng nhớ trên Heap cho con trỏ p với kích thước bằng kích thước của kiểu dữ liệu và gán địa chỉ cua vùng này cho p. Khi đó biến động định kiểu p^ sẽ truy cập vùng được cấp phát chừng nào p còn giữ địa chỉ vùng này. Mọi thao tác trên biến thông thường đều được áp dụng cho p^.
Vùng nhớ đã cấp phát cho con trỏ p bằng thủ tục New(p) sẽ được thu hồi nhờ thủ tục Dispose (p). Vùng nhớ đã cấp phát sẽ được hệ thống bảo vệ cho đến khi được thu hồi.
4) Danh sách liên kết
Một trong những ứng dụng quan trọng nhất của cấp phát động là tạo ra những cấu trúc dữ liệu động, cho phép khai thác linh hoạt và tối đa bộ nhớ. Các cài đặt dùng cấu trúc dữ liệu động không bị hạn chế (về lôgic) bởi kích thước của dữ liệu, và đặc biệt thuận lợi khi phải dùng thường xuyên các thao tác chèn hoặc xóa.
Danh sách liên kết là một dãy các phần tử có cùng kiểu dữ liệu, trong đó cần chỉ rõ mối liên kết trước-sau của các phần tử trong danh sách. Một dạng cài đặt thường gặp của danh sách liên kết là dùng mảng, trong đó mối liên kết được ẩn dưới các giá trị kề nhau của chỉ số. Việc dùng mảng cho phép truy cập nhanh đến các phần tử của danh sách nhờ các giá trị chỉ số. Tuy nhiên các hạn chế của việc dùng mảng là:
Khai thác bộ nhớ không linh hoạt bộ nhớ do phải khai báo trước.
Không thể làm việc với những danh sách lớn hơn 64 Kb vì mảng cần được cấp một vùng nhớ liên tục.
Các thao tác chèn, xóa đòi hỏi phải dồn chỉ số cho các phần tử mảng.
Việc cấp phát động cho các phần tử của danh sách cho phép khai thác bộ nhớ tốt hơn. Một mặt, nó không phụ thuộc vào kích thước danh sách vì không phải khai báo trước. Mặt khác, do các phần tử của danh sách được cấp phát riêng rẽ nên danh sách không bị hạn chế bởi giới hạn 64 Kb. Ngoài ra, các thao tác chèn, xóa đòi hỏi không phải dồn phần tử.
Để xây dựng danh sách liên kết bằng cấp phát dộng mỗi phần tử của nó (mà ta sẽ gọi là nút - node) cần phải xác định hai thành phần: Một là nội dung dữ liệu mà nút lưu trữ, hai là địa chỉ của nút kế tiếp. Ta dùng kiểu bản ghi để định nghĩa một nút như vậy:
Type
DataType = ....... {kiểu dữ liệu}
PtrType = ^Node;
Node = record
Data: DataType; {lưu trữ dữ liệu}
Next: PtrType; {trỏ đến nút kế tiếp}
End;
Khai báo trên định nghĩa kiểu PtrType trỏ tới Node, trong đó Node là kiểu bản ghi mô tả một nút gồm hai trường. Trường Data dùng để lưu với giả thiết tên kiểu là DataType (là một kiểu dữ liệu nào đấy đã được định nghĩa, có thể gồm nhiều thành phần) còn trường Next thuộc kiểu PtrType, dùng để lưu địa chỉ của nút kế tiếp. Trong những khai báo như ở trên thì PtrType cần được định nghĩa trước Node.
Để quản lý danh sách, cần có một biến toàn thể thuộc kiểu PtrType lưu địa chỉ của nút đầu tiên trong danh sách. Ta sẽ đặt tên cho biến này là First:
Var
First: PtrType;
Từ giá trị của First ta có thể truy cập đến nút đầu tiên, sau đó từ trường Next của nút này, ta có thể truy cập tới nút thứ hai,.... Để báo hết danh sách, trường Next của nút cuối cần trỏ vào Nil. Bằng cách như vậy, ta có thể truy cập được toàn bộ các nút của danh sách.
- Để khởi tạo danh sách rỗng (chưa có nút nào), ta gán Nil cho con trỏ First:
First:=Nil;
- Duyệt danh sách: Để lần lượt đi qua các nút của danh sách, cần phải khởi động một con trỏ CurrPtr trỏ đến nút đầu tiên, rồi đi tiếp qua danh sách theo các trường liên kết và xử lý dữ liệu trong mỗi nút.
- Xây dựng danh sách: Đây là công việc sẽ gặp trong bài toán của đề tài. Trong bài toán thường xảy ra tình huống chèn một nút mới vào cuối danh sách. Công việc này đòi hỏi phải tổ chức thêm con trỏ Last luôn trỏ tới cuối danh sách nhằm không phải tìm kiếm lại. Như thế sau mỗi lần nối, phải cập nhập lại giá trị cho con trỏ này. Ngoài ra việc nối vào một danh sách rỗng phải được xử lý riêng vì khi đó không có nút đi trước.
First := Nil;
While not Stop do
Begin
New (TempPtr);
TempPtr^.Data:= Item;
If First = Nil then
First:= TempPtr;
else
Last^.Next:=Tempptr;
Last:=Tempptr;
Last^.Next:=Nil;
End;
- Tìm kiếm một nút trong danh sách: Giả sử cần tìm một nút trong danh sách có nội dung dữ liệu là Item (có kiểu DataType). Việc tìm kiếm được tiến hành tuần tự theo chiều duyệt danh sách bắt đầu từ First nhờ con trỏ CurrPtr. Mỗi khi đi đến một nút, vùng dữ liệu của Currptr lại được so sánh với Item. Nếu tìm thấy, con trỏ Currptr sẽ xác định nút cần tìm, trái lại con trỏ Currptr sẽ có giá trị Nil.
III.Xây dựng phương án giải quyết bài toán
Chương trình để giải quyết bài toán sẽ thực hiện 2 công việc chính, thống kê kí tự đơn (liệt kê các kí tự có trong văn bản, số lần xuất hiện của mỗi kí tự) và thống kê số lần xuất hiện của kí tự đơn sau một kí tự đơn khác trong kí tự đôi (xét xem kí tự này đứng sau kí tự kia bao nhiêu lần trong toàn bộ văn bản).
1) Mô tả phương án giải quyết bài toán
Để làm được các việc đó, chương trình cần phải trải qua 3 bước chính:
- Bước 1: Lập danh sách liên kết chứa toàn bộ kí tự đơn của văn bản. Mỗi nút của danh sách chứa một kí tự đơn:
Đầu tiên tiến hành đọc file văn bản đầu vào theo từng ký tự, dùng thủ tục Read(f, ch); nhận các ký tự chuẩn (các ký tự tạo thành từ). Sau mỗi lần có được một kí tự
thì tiến hành tạo nút mới có phần nội dung chứa kí tự đó và tiến hành chèn nút này vào cuối danh sách.
Như vậy sau bước này ta có một danh sách liên kết chứa các kí tự đơn của file văn bản nguồn. Đây chỉ là danh sách trung chuyển để tiện cho việc xử lý dữ liệu sau này mà chưa phải là danh sách thống kê kí tự chuẩn.
Thực ra ngay từ khi đọc file văn bản nguồn như ở bước này ta đã có thể tạo ra danh sách thống kê kí tự đơn hoàn chỉnh. Danh sách này sẽ có phần nội dung gồm 2 trường:
Trường 1: Chứa nội dung kí tự
Trường 2: Chứa số lần xuất hiện kí tự trong file văn bản
Tuy nhiên, bài toán còn liên quan đến việc thống kê kí tự đôi. Vì vậy ta cần có một danh sách chứa kí tự đơn của văn bản mà vẫn giữ nguyên trật kí tự như trong văn bản, kí tự nào đứng trước trong văn bản thì vẫn đứng trước trong danh sách.
Sau khi có được một danh sách chứa các kí tự đôi của văn bản được xếp đúng trật tự, ta chuyển sang bước 2.
- Bước 2: Lập danh sách thống kí tự từ đơn và đưa kết quả ra file văn bản.
Từ danh sách đã thu được từ bước 1, ta tiến hành thực hiện công việc thứ nhất của bài toán: thống kê kí tự đơn trong văn bản.
Để thống kê kí tự đơn rồi đưa kết quả ra một file văn bản, trước hết cần phải lập một danh sách thống kê kí tự đơn hoàn chỉnh với phần nội dung gồm hai trường:
Trường 1: Term: char - chứa kí tự
Trường 2: lanxh: integer; chứa số lần xuất hiện của kí tự đó.
Tiến hành duyệt từng nút của danh sách thu được từ bước 1 để lấy ra lần lượt từng kí tự đơn của file văn bản. Các kí tự này sẽ qua một thủ tục để kiểm tra đã có trong danh sách thống kê hay chưa, nếu chưa có thì thêm một nút có nội dung term là kí tự đó và đưa vào cuối danh sách, số lần xuất hiện của kí tự lúc này được đưa vào là 1. Nếu kí tự đã có trong danh sách thì tìm đến vị trí nút chứa kí tự đó, tăng trường số lần xuất hiện của kí tự lên 1.
Sau khi đã có một danh sách thống kê kí tự đơn hoàn chỉnh, cung cấp đầy đủ thông tin về nội dung và số lần xuất hiện của kí tự , ta sẽ tiến hành duyệt danh sách này để đưa ra file kết quả. File kết quả cũng là file văn bản, có tên do người dùng tự đặt, tên file được nhập từ bàn phím.
- Bước 3: Thống kê số lần xuất hiện của một kí tự liền sau một kí tự (thống kê từ đôi).
Với danh sách thu được từ bước 1, tổ chức 2 con trỏ currptr và back. Ban đầu currptr chỉ vào nút đầu tiên của danh sách, back chỉ vào nút liền sau nút trỏ bởi currptr. Như vậy khi duyệt danh sách bằng 2 con trỏ này ta lần lượt nhận được từ đứng trước (nhờ con trỏ currptr) và từ đứng sau (nhờ con trỏ back). Lập 2 con trỏ khác là currptr2 và back2 với kiểu như 2 con trỏ currptr và back để tìm số lần lặp lại của 2 từ đơn liền nhau.
Mỗi khi có được một kết quả hoàn chỉnh (kí tự đơn này đứng sau kí tự đơn kia bao nhiêu lần), tiến hành ghi luôn kết quả này ra một file văn bản chứa kết quả, tên cũng do người dùng đặt và nhập từ bàn phím.
2) Mô tả chương trình
Chương trình giải quyết bài toán (có tên là THONG_KE_ky_tu) có định nghĩa kiểu danh sách và khai báo biến như sau:
Type
ptrtype = ^node; {kiểu con trỏ trỏ vào danh sách}
node = record {định nghĩa danh sách theo kiểu bản ghi}
data: char;
next: ptrtype;
end;
var
first: ptrtype; {con trỏ trỏ vào nút đầu tiên của danh sách, là biến toàn cục}
name1, name2, name3: string; {các tên file văn bản}
Chương trình gồm 3 thủ tục chính:
procedure Creatlist (name: string);
procedure Thongkekytudon (name: string);
procedure Thongkekytudoi (name: string);
+) Thủ tục procedure Creatlist (name: string); thực hiện bước 1: tạo danh sách chứa toàn bộ ký tự đơn của file văn bản có tên name, vẫn giữ nguyên trật tự như trong file văn bản. Thủ tục này gồm một số hàm và thủ tục sau:
- Hàm function Getchar: char; , trả lại một ký tự đơn hợp lệ (khác các dấu và ký tự đặc biệt) lấy được từ file văn bản, nếu không có trả lại rỗng. Nội dung của hàm này như sau:
const {khai báo mảng chứa các ký tự không hợp lệ}
delimitset: set of char = [chr(0), chr(13), chr(10), chr(0). . Chr(64),
chr(91). . Chr(96), chr(123). . Chr(127)];
Var
w ,ch: char;
more: boolean;
begin
ch: =chr(0);
more: =true;
while not eof(f) do
begin
read(f, ch); {đọc từng ký tự của file văn bản vào biến ch}
more: = ch in delimitset;
if not more then {nếu ký tự là hợp lệ}
begin
getchar: =ch;
break; {thoát ngay ra khỏi vòng lặp để có getchar:=ch hợp lệ}
end;
end;
end;
- Thủ tục procedure Insertlist (Item: char; var last: ptrtype); chèn một nút mới có nội dung Item vào cuối danh sách, nút cuối danh sách được định vị bởi tham biến last kiểu con trỏ. Nội dung của thủ tục này như sau:
var
tempptr: ptrtype;
begin
new (tempptr); {xin cấp phát nút mới}
tempptr^.data: = Item; {nội dung nút mới là Item}
if first=nil then {trường hợp danh sách rỗng}
first: =tempptr;
else
last^.next: =tempptr; {gắn nút mới vào cuối danh sách}
last: =tempptr; {xác định lại con trỏ last}
last^.next: =nil;
end;
Và đây là phần thân chương trình của thủ tục procedure Creatlist (name: string);
begin
assign(f, name); reset(f); {mở file văn bản nguồn}
first: =nil; last: =first; {khởi tạo danh sách}
while not eof(f) do
begin
Item: =getchar; {lấy từng ký tự đơn vào biến Item}
if (Itemchr(0)) and ((Itemchr(11)) {lọc để đảm bảo Item là hợp lệ}
then insertlist(Item, last); {chèn vào danh sách}
end;
close(f); {đóng file văn bản nguồn để bảo vệ dữ liệu}
end;
+) Thủ tục procedure thongkekytudon (name: string); thống kê từ đơn và ghi kết quả ra file có tên name. Thủ tục này có phần khai báo như sau:
type
ptrrec = ^rec; {định nghĩa một kiểu con trỏ mới, trỏ vào danh sách thống kê từ}
rec = record {định nghĩa từng nút của danh sách}
term: char; {chứa từ}
lanxh: integer; {chứa số lần xuất hiện của từ}
nextrec: ptrrec; {con trỏ trỏ tới nút kế tiếp}
end;
var
f: text; {biến gắn với tên file chứa kết quả thống kê từ đơn}
firstrec, lastrec: ptrrec; {2 con trỏ trỏ vào đầu và cuối danh sách thống kê}
Thủ tục này bao gồm các hàm và thủ tục như sau:
- Hàm function InRec (w: char): boolean;
{tìm trong danh sách rec nút có nội dung w}
var
currrec: ptrrec;
begin
currrec: = firstrec; {bắt đầu tìm từ nút đầu tiên của danh sách}
inrec: =false;
while (currrecnil) do
begin
if currrec^.term=w then
begin
inrec: =true;
break; {ngắt ra khỏi vòng lặp nếu đã tìm thấy}
end;
currrec: = currrec^. Nextrec; {không tìm thấy, tiếp tục chuyển tới
nút sau}
end;
end;
- Thủ tục procedure InsertRec (L: char; N: integer; var lastrec: ptrrec); thêm một nút mới vào cuối danh sách:
Var
tempptr: ptrrec;
begin
new (tempptr); {xin cấp phát một nút mới}
tempptr^.term: = L; {nạp nội dung cho nút mới}
tempptr^.lanxh: =N;
if firstrec=nil then {nếu danh sách rỗng}
firstrec:=tempptr
else
lastrec^.nextrec: =tempptr; {nối vào cuối danh sách}
lastrec: =tempptr; {định vị lại con trỏ last}
lastrec^.nextrec: =nil;
end;
- Thủ tục procedure Taodanhsachkytudon; tạo danh sách thống kê ký tự đơn hoàn chỉnh để chuẩn bị đưa ra file kết quả.
var
currptr, currptr2: ptrtype;
ch: char;
count: integer;
begin
currptr: =first;
while currptrnil do {duyệt danh sách ở bước 1 để lấy từ}
begin
ch: =currptr^.data; {lấy từng từ vào biến ch}
currptr2: =first;
count: =0;
while currptr2nil do {tìm số lần lặp lại của từ}
begin
if (currptr2^.data=ch) then count: =count+1;
currptr2: =currptr2^.next;
end;
if not inrec(ch) then insertrec(ch, count, lastrec); {kiểm tra từ đã có trong danh sách thống kê chưa, nếu chưa có thì đưa vào cuối danh sách}
currptr: =currptr^.next;
end;
end;
- Thủ tục procedure Ghirafile; duyệt danh sách thống kê ký tự đơn (rec) để ghi ra file kết quả.
var
currptr: ptrrec;
begin
assign (f, name); rewrite(f); {mở file kết quả để ghi}
currptr: =firstrec; {bắt đầu duyệt từ nút đầu tiên}
while currptrnil do
begin {duyệt danh sách để ghi lên file f}
writeln(f, currptr^.term, ' ': 16-length(currptr^.term), 'xuat hien: ',
currptr^.lanxh: 10, ' lan');
currptr:=currptr^.nextrec;
end;
close(f);
end;
- Phần thân chương trình của thủ tục procedure thongkekytudon (name: string);là
begin
firstrec: =nil;
lastrec: =firstrec;
taodanhsachkytudon;
ghirafile;
end;
+) Thủ tục procedure thongkekytudoi(name: string); thống kê số lần lặp lại của một ký tự đơn sau một ký tự đơn khác trong ký tự đôi và ghi kết quả ra file văn bản. Thủ tục này có nội dung như sau:
var
currptr, back, currptr2, back2: ptrtype; {khai báo các con trỏ để duyệt danh sách
thu được từ bước 1}
w1, w2: char;
count: integer;
f: text;
begin
assign (f, name); rewrite(f); {mở file kết quả để ghi}
currptr: =first;
back: =currptr^.next;
while (currptrnil) and (backnil) do
begin
w1: =currptr^.data; {lấy ký tự đứng trước}
w2: =back^.data; {lấy ký tự đứng sau}
currptr2: =first;
back2: =currptr2^.next;
count: =0;
while ((currptr2nil) and (back2nil)) do {duyệt danh sách để
tìm số lần lăp lại}
begin
if ((currptr2^.data=w1) and (back2^.data=w2)) then
count: =count+1;
currptr2: =currptr2^.next;
back2: =back2^.next;
end;
writeln (f, w2, ' sau ', w1, ' ', count: 10, ' lan'); {ghi thông tin ra file f}
currptr: =currptr^.next;
back: =back^.next;
end;
close(f);
end;
3) Nội dung chương trình:
Program THONG_KE_ky_tu;
TYPE
ptrtype = ^node;
node = record
data: char;
next: ptrtype;
end;
VAR
first: ptrtype;
name1, name2, name3: string;
procedure Creatlist (name: string);
{tao lap danh sach chua cac tu cua file}
Var
f: text;
Item: char;
last: ptrtype;
Function Getchar: char;
Const
delimitset: set of char = [chr(0), chr(13), chr(10), chr(0). . Chr(64),
chr(91). . Chr(96), chr(123). . Chr(127)];
Var
ch: char;
more: boolean;
Begin
ch: =chr(0);
more: =true;
while not eof(f) do
begin
read(f, ch);
more: = ch in delimitset;
if not more then
begin
getchar: =ch;
break;
end;
end;
End;
Procedure Insertlist (Item: char; var last: ptrtype);
Var
tempptr: ptrtype;
Begin
new (tempptr);
tempptr^. Data: = Item;
if first=nil then
first: =tempptr
else
last^. Next: =tempptr;
last: =tempptr;
last^. Next: =nil;
End;
Begin
assign(f, name); reset(f);
first: =nil; last: =first;
while not eof(f) do
begin
Item: =getchar;
if (itemchr(0)) and (itemchr(11)) then
begin
insertlist(Item, last);
end;
end;
close(f);
End;
procedure thongkekytudon(name: string);
{thong ke ky tu don va ghi ket qua ra file co ten name}
Type
ptrrec = ^rec;
rec = record
term: char;
lanxh: integer;
nextrec: ptrrec;
end;
Var
f: text;
firstrec, lastrec: ptrrec;
Function InRec(w: char): boolean;
{tim w trong list}
Var
currrec: ptrrec;
Begin
currrec: = firstrec;
inrec: =false;
while (currrecnil) do
begin
if currrec^. Term =w then
begin
inrec: =true;
break;
end;
currrec: = currrec^. Nextrec;
end;
End;
Procedure InsertRec (L: char; N: integer; var lastrec: ptrrec);
Var
tempptr: ptrrec;
Begin
new (tempptr);
tempptr^. Term: = L;
tempptr^. Lanxh: =N;
if firstrec=nil then
firstrec: =tempptr
else
lastrec^. Nextrec: =tempptr;
lastrec: =tempptr;
lastrec^. Nextrec: =nil;
End;
Procedure Taodanhsachkytudon;
Var
currptr, currptr2: ptrtype;
ch: char;
count: integer;
Begin
currptr: =first;
while currptrnil do
begin
ch: =currptr^. Data;
currptr2: =first;
count: =0;
while currptr2nil do
begin
if (currptr2^. Data=ch) then count: =count+1;
currptr2: =currptr2^. Next;
end;
if not inrec(ch) then insertrec(ch, count, lastrec);
currptr: =currptr^. Next;
end;
end;
procedure ghirafile;
var
currptr: ptrrec;
begin
assign (f, name); rewrite(f);
currptr: =firstrec;
while currptrnil do
begin
writeln(f, currptr^. Term, ' ': 16-length(currptr^. Term), 'xuat hien: ',
currptr^. Lanxh: 10, ' lan');
currptr: =currptr^. Nextrec;
end;
close(f);
end;
Begin
firstrec: =nil;
lastrec: =firstrec;
taodanhsachkytudon;
ghirafile;
End;
procedure thongkekytudoi(name: string);
{thong ke so lan xuat hien cua mot ky tu lien sau mot ky tu khac trong van ban
va ghi ket qua ra file co ten name}
Var
currptr, back, currptr
Các file đính kèm theo tài liệu này:
- 362.doc