Kỹ thuật nén tập tin thường được áp dụng cho các tập tin văn bản Trong đó có một số kí tự nào đó có xác suất xuất hiện nhiều hơn các kí tự khác, các tập tin ảnh bitmap Mà có thể có những
Trang 2TRƯỜNG ĐẠI HỌC CNTT & TRUYỀN THÔNG
Người hướng dẫn khoa học: PGS.TS Nguyễn Hữu Điển
Phản biện 1: TS Lê Quang Minh
Phản biện 2: TS Trần Đức Sự
Luận văn sẽ được bảo vệ trước Hội đồng chấm luận văn họp tại:
Trường Đại học Công nghệ thông tin & Truyền thông
Vào hồi 11 giờ 00 ngày 09 tháng 11 năm 2013
Có thể tìm hiểu luận văn tại:
- Trung tâm học liệu Đại học Thái Nguyên
- Thư viện trường Đại học CNTT & Truyền thông Thái Nguyên
Trang 3MỞ ĐẦU
1 Đặt vấn đề
Nén dữ liệu là một kỹ thuật quan trọng trong rất nhiều lĩnh vực khác nhau Chính nhờ có kỹ thuật nén dữ liệu mà ngày nay chúng ta có những phương tiện truyền thông hiện đại phục vụ cho cuộc sống như truyền hình cáp, truyền hình số, điện thoại, internet, các hệ thống lưu trữ, văn bản và rất nhiều khía cạnh khác Do đó kỹ thuật nén dữ liệu ngày càng được quan tâm
và phát triển nhiều hơn
Tiếng Việt là một ngôn ngữ thuộc hệ thống chữ cái Latinh, sử dụng nhiều dấu đi kèm với nguyên âm, ngoài bảng chữ cái của tiếng Anh, tiếng Việt còn có thêm các ký tự:
Sáu nguyên âm a, e, i, o, u, y với 5 dấu thanh (sắc, huyền, hỏi, ngã, nặng) tổ hợp thành 30 ký tự
Sáu nguyên âm ă, â, ê, ô, ơ, ư với sáu dấu thanh (sắc, huyền, hỏi, ngã, nặng, không dấu) tổ hợp thành 36 ký tự
Một phụ âm đặc biệt đ
Vậy cần thêm (30 + 36 +1) x 2 = 134 ký tự cho tiếng Việt
Với bảng mã ASCII 8 bit sử dụng phổ biến trên máy tính, chúng ta có thể mã hóa 256 ký tự Tuy nhiên, các ký tự có mã từ 0 đến 127 đã được chuẩn hóa và thuộc diện “cấm vi phạm” vì vậy chỉ còn 128 chỗ (mã từ 128 đến 255)
là được “tự do” Vậy nếu xây dựng mỗi chứ ứng với một mã thì sử dụng hết vùng tự do mà vẫn thiếu 134 – 128 = 6 chỗ
Hiện nay chúng ta đang sử dụng chuẩn Unicode để lưu trữ các ký tự tiếng Việt Như chúng ta biết chuẩn Unicode là chuẩn 2byte, do vậy khi lưu trữ các văn bản tiếng Việt trên các hệ thống lưu trữ sẽ xẩy ra tình trạng dư thừa dữ liệu Điều này dẫn đến việc lưu trữ và xử lý sẽ lãng tài nguyên hệ
Trang 4thống, khi truyền tải trên các đường truyền mạng sẽ chiếm băng thông nhiều hơn Từ các yêu cầu thực tế đó đòi hỏi chúng ta phải loại bỏ sự dư thừa dữ
liệu đó trước khi lưu trữ và xử lý Chính vì thế em chọn đề tài “Nén dữ liệu
tiếng Việt sử dụng thuật toán mã hóa số học”
2 Đối tượng và phạm vi nghiên cứu
- Các chuẩn lưu trữ tiếng Việt (Unicode, TCVN3, VNI-Vindows…)
- Các phương pháp và kỹ thuật nén dữ liệu
- Các phần mềm nén dữ liệu hiện nay
3 Hướng nghiên cứu đề tài
- Nghiên cứu các phương pháp nén dữ liệu như nén bảo toàn dữ liệu (lossless data compression) và nén mất mát dữ liệu (lossy data compression)
- Nghiên cứu các kỹ thuật nén dữ liệu như: kỹ thuật xử lý sự lặp lại của xâu (RLE), mã hóa Huffman, kỹ thuật nén LZW (Lempel - Zip và Welch)…
- Nghiên cứu về kỹ thuật nén bảo toàn dữ liệu Arithmetic Coding (Phương pháp mã hóa số học)
- Cài đặt thực nghiệm việc nén dữ liệu bằng Arithmetic Coding
- Phân tích, so sánh và đánh giá kết quả thực nghiệm với các kỹ thuật nén dữ liệu (văn bản tiếng Việt) khác
Trang 54 Phương pháp nghiên cứu
- Nghiên cứu các tài liệu về các kỹ thuật mã hóa và nén dữ liệu
- Tìm hiểu các chuẩn tiếng Việt hiện nay ở Việt Nam
- Khảo sát thực tế các phần mềm nén dữ liệu hiện nay đối với việc nén các văn bản tiếng Việt
- Phân tích, đánh giá các kỹ thuật (thuật toán) nén dữ liệu
- Cài đặt kỹ thuật nén Arithmetic Coding
- Triển khai thử nghiệm trên các loại dữ liệu văn bản tiếng Việt
5 Ý nghĩa khoa học và ý nghĩa thực tiễn của đề tài
- Nghiên cứu hoàn thiện các kỹ thuật nén bảo toàn dữ liệu cho các văn bản tiếng Việt
- Xây dựng ứng dụng nén dữ liệu cho các văn bản tiếng Việt
Trang 6Chương 1: TỔNG QUAN VỀ NÉN DỮ LIỆU
1.1 Tổng quan về nén dữ liệu
1.1.1 S ơ l ượ c v ề nén d ữ li ệ u
1.1.1.1 Khái niệm nén dữ liệu
Nén dữ liệu là quá trình làm giảm lượng thông tin “dư thừa” trong dữ liệu gốc và do vậy, lượng thông tin thu được sau nén thường nhỏ hơn so với
dữ liệu gốc rất nhiều
1.1.1.2 Nguyên tắc nén dữ liệu
Thông thường, hầu hết các tập tin trong máy tính có rất nhiều thông tin
dư thừa, việc thực hiện nén tập tin thực chất là mã hoá lại các tập tin để loại
bỏ các thông tin dư thừa
Nhìn chung không thể có phương pháp nén tổng quát nào cho kết quả tốt đối với tất cả các loại tập tin vì nếu không ta sẽ áp dụng n lần phương pháp nén này để đạt được một tập tin nhỏ tuỳ ý Kỹ thuật nén tập tin thường được
áp dụng cho các tập tin văn bản (Trong đó có một số kí tự nào đó có xác suất xuất hiện nhiều hơn các kí tự khác), các tập tin ảnh bitmap (Mà có thể có những mảng lớn đồng nhất), các tập tin dùng để biểu diễn âm thanh dưới dạng
số hoá và các tín hiệu tương tự (analog signal) khác (Các tín hiệu này có thể
có các mẫu được lặp lại nhiều lần) Ðối với các tập tin nhị phân như tập tin chương trình thì sau khi nén cũng không tiết kiệm được nhiều
Ngoài ra, trong một số trường hợp để nâng cao hệ số nén người ta có thể bỏ bớt một số thông tin của tập tin
1.1.2 Các ph ươ ng pháp nén d ữ li ệ u
1.1.2.1 Nén bảo toàn dữ liệu
Đó là mô hình nén dữ liệu mà nó cho phép người sử dụng bảo toàn
thông tin trong suốt quá trình nén Điều này được giải thích như sau:
Trang 7Giả sử ta có dữ liệu nguồn là A và dữ liệu nén là A' Sau khi ta giải nén A' thì được tập A'' mà tập A'' hoàn toàn giống với tập A ban đầu khi được giải nén Thông thường, kỹ thuật này được áp dụng với các loại dữ liệu như văn bản vì độ chính xác của văn bản
1.1.2.2 Nén hao hụt dữ liệu
Trong kỹ thuật nén, bên cạnh nén bảo toàn thì người ta còn đưa ra khái niệm nén không bảo toàn (hay còn gọi là nén hao hụt dữ liệu) Nén không bảo toàn là mô hình nén dữ liệu mà tính bảo toàn của dữ liệu không được coi trọng Nó có nghĩa là nếu ta có tập dữ liệu A, tập nén A' thì sau khi giải nén ta thu được tập A'' khác tập A ban đầu Kỹ thuật này thường áp dụng cho việc nén dữ liệu là các loại tệp ảnh vì nói chung nó cũng không ảnh hưởng gì nhiều đến hình dạng ảnh
1.2 Các kỹ thuật nén dữ liệu văn bản
1.2.1 X ử lý l ặ p l ạ i c ủ a xâu ký t ự (Run – Length Encoding)
Mục đích của thuật toán là tìm ra được ký tự lặp lại nhiều lần và số lần lặp lại của ký tự đó, thay thế cụm lặp lại bằng một biểu diễn nhỏ gọn hơn
Có thể biểu diễn rút gọn dưới dạng cặp 3 ký hiệu (r,s,l) với s là ký hiệu của một dãy các ký tự nằm trong bảng chữ cái, r và l sẽ là các ký hiệu không
được xuất hiện trong bảng chữ cái, tùy từng trường hợp mà r và l lại có ý
nghĩa khác nhau
Ví dụ: Cho chuỗi đầu vào là MMMMMMM (chữ M được lặp lại 7 lần), chuỗi này có thể thay thế bằng (r,7,M) hay viết tắt là r7M r với ý nghĩa ký hiệu cho việc xuất hiện sự lặp lại (repeating) đòi hỏi chữ r không được xuất hiện trong bảng chữ cái của đầu vào
Cho chuỗi đầu vào là ABCDEFG (không xuất hiện sự lặp lại) chuỗi này có thể thay thế bằng (n,7,ABCDEFGH), hay viết tắt là n7ABCDEFG n
Trang 8với ý nghĩa là ký hiệu cho việc không xuất hiện sự lặp lại (non-repeating), chữ
n không được xuất hiện trong bảng chữ cái đầu vào
Thuật toán này hiệu quả nếu như dữ liệu đầu vào gồm nhiều ký tự bị lặp lại liên tiếp Ký tự đầu vào có thể ở dạng chữ trong bảng chữ cái, có thể là các bit 0, 1 nhị phân; các thông số về màu của các điểm ảnh, cũng có thể là các khối hợp thành của dữ liệu kiểu âm thanh Trên thực tế, thuật toán này vẫn còn được áp dụng cho tới ngày nay: thuật toán HDC (hardware data compression), được sử dụng trong các ổ băng kết nối với hệ thống máy tính IBM, và cả thuật toán tương tự được dùng trong chuẩn SNA (System network architecture) của IBM
1.2.2 Mã hóa Huffman
1.2.2.1 Mã Huffman tĩnh
* Nguyên lý:
Nguyên lý của phương pháp Huffman là mã hoá các bytes trong tệp
dữ liệu nguồn bằng biến nhị phân Nó tạo mã độ dài biến thiên là một tập hợp các bits Đây cũng là một phương pháp nén kiểu thống kê, những ký
tự xuất hiện nhiều hơn sẽ có mã ngắn hơn
Mã Huffman có một tính chất quan trọng: mã của một ký hiệu này không thể là phần đầu của mã một ký hiệu khác
Nếu như một ký hiệu được mã hoá bằng tổ hợp nhị phân 101 thì tổ hợp 10110 không thể là mã của một ký hiệu khác trong tệp nguồn Do đó khi giải mã cần phải đọc lần lượt các bit cho đến khi gặp mã của ký hiệu nào đó
Trang 9phần 1 bít, công việc kết thúc khi không thể tiến hành phân chia tiếp thì cây Huffman lại được thiết kế từ dưới lên, bắt đầu từ các lá của cây và công việc kết thúc tại điểm gốc
Trang 10{{{{u, ô}, 1}, e}, {a, o}}
Bước 1: Tìm hai ký tự có trọng số nhỏ nhất ghép lại làm một, trọng số của ký
tự mới bằng tổng trọng số của hai ký tự đem ghép
Bước 2: Trong khi số lượng ký tự trong danh sách còn lớn hơn một thì thực
hiện bước một, nếu không thì thực hiện bước ba
Bước ba: Tách ký tự cuối cùng và tạo cây nhị phân với qui ước bên trái mã 0,
bên phải mã 1
Thuật toán giải nén:
Bước 1: Đọc lần lượt từng bit trong tập tin nén và duyệt cây nhị phân đã được
xác định cho đến khi hết một lá Lấy ký tự ở lá đó ghi ra tệp giải nén Bước 2: Trong khi chưa hết tập tin nén thì thực hiện bước một, ngược lại thực
hiện bước ba
Bước 3: Kết thúc thuật toán
Trang 11Một số những hạn chế của mã Huffman:
+ Mã Huffman chỉ thực hiện được khi biết được tần xuất xuất hiện của các ký tự
+ Mã Huffman chỉ giải quyết được độ dư thừa phân bố ký tự
+ Huffman tĩnh đòi hỏi phải xây dựng cây nhị phân sẵn chứa các khả năng Điều này đòi hỏi thời gian không ít do ta không biết trước kiểu dữ liệu
sẽ được thực hiện nén
+ Quá trình giải nén phức tạp do chiều dài mã không biết trước cho đến khi ký tự đầu tiên được tìm ra
1.2.2.2 Thuật toán Huffman động
Trong thuật toán Huffman động chúng ta sử dụng hai cây nhị phân cân và một
Huffman trong quá trình nén văn bản
Trong quá trình nén dữ liệu, ta tiến hành thống kê các ký tự Nhờ việc thống
kê này mà sinh ra bộ nén
Thuật toán nén:
Bước 1: Khởi tạo bảng mã Huffman(front tree) với ký tự đặc biệt, có số đếm
bằng 1
Bước 2: Tạo mã thứ tự theo nguyên tắc cân bằng
Bước 3: While not eof(f) do
Begin
Getchar-> ch
If ch thuộc bảng mã thứ tự then
Begin
Ghi mã 0/1 của ký tự đó và ký tự đặc biệt ra tệp đích
Xóa ký tự đó ở bảng mã thứ tự, thêm ký tự đó vào bảng mã Huffman (trong cây front tree) với số đếm bằng 1
End Else
Begin
Trang 12If ch thuộc bảng mã Huffman then
Begin
Tăng số đếm của ký tự đó lên một đơn vị
If số đếm của ký tự đó lớn hơn số đếm của ký tự ngay trên nó then Begin
Tìm một ký tự, giảm số đếm của ký tự đó đi một đơn vị
If dưới ký tự đó là ký tự đặc biệt then
Giảm số đếm của ký tự đặc biệt đi một đơn vị
Loại ký tự đó ra khỏi bảng mã Huffman
Tăng số lượng ký tự ở cây thứ tự lên một
Giảm số lượng ký tự ở cây Huffman đi một
Thêm ký tự vừa loại ra khỏi bảng mã Huffman đó và bảng mã thứ
Trang 13Bước 4: Dừng chương trình
Thuật toán giải nén:
Bước 1: Khởi tạo bảng mã thứ tự theo nguyên tắc cân bằng
Bước 2: While not eof(f) do
Tra trong bảng mã thứ tự và ghi ký tự đó ra tệp đích
Thêm ký tự đó vào bảng mã Huffman với số đếm bằng 1
End;
If ký tự đặc biệt đó chỉ tới bảng mã Huffman then
Begin
Tra trong bảng mã Huffman và ghi ký tự đó ra tệp đích
Tăng số đếm của ký tự lên 1 đơn vị
If số đếm của ký tự đó lớn hơn số đếm của ký tự trên nó then Begin
Tìm ký tự nào đó giảm đi 1 đơn vị
If số đếm của ký tự đó < số đếm của ký tự đứng trước nó then Begin
If bên dưới nó là ký tự đặc biệt then
Giảm số đếm của ký tự đặc biệt đó đi 1
Đổi chỗ hai ký tự đó
End;
If số đếm của ký tự đó sau khi giảm đi 1 bằng không then
Begin
Trang 14Tăng số lượng ký tự ở cây thứ tự lên một
Giảm số lượng ký tự ở cây Huffman đi một
Loại ký tự đó ra khỏi bảng mã Huffman
Thêm ký tự vừa loại ra vào bảng mã thứ tự
Đánh giá: Quá trình mã và giải mã tương đối chậm do phải xây dựng cây nhị
phân ứng với dữ liệu nhập Thuật toán nén Huffman thường được dùng để
nén các tệp dạng văn bản, các tệp có kích thước lớn
1.2.3 Thu ậ t toán LZW
Thuật toán này là sự chuyển giao của thuật toán LZ78 Như chúng ta đã
biết ở thuật toán LZ78, việc lưu trữ các ký tự theo sau mỗi đoạn thường gây
lãng phí về bộ nhớ nên hiệu quả nén không cao Thuật toán LZW quản lý bằng cách loại bỏ ký tự sau mỗi đoạn do đó đầu ra của mỗi đoạn chỉ chứa con trỏ mà thôi Thuật toán này lưu trữ bằng việc chuẩn bị một danh sách các
đoạn bao gồm rất nhiều ký tự trong đầu vào là một bảng chữ cái nào đó, nó
thực hiện một quá trình mở rộng các bảng chữ cái hay nói cách khác là nó dùng ký tự bổ sung để biểu diễn lại các chuỗi của ký tự chính quy Để nén LZW trên mã ASCII 8 bits ta cần mở rộng bảng chữ cái bằng cách dùng 9 bits hay nhiều hơn 256 ký tự bổ sung mà mã 9 bits cung cấp được dùng để lưu trữ các chuỗi mã được quyết định từ các chuỗi trong nguồn tin Thuật toán sẽ không đạt hiệu quả nén cao nếu có những điều kiện sau:
+ Nguồn tin không đồng nhất và đặc tính dư thừa của nó thay đổi trong suốt tập tin
+ Nguồn tin dài một cách đáng kể vượt quá tầm giới hạn của bảng chuỗi
Thuật toán nén:
Bước 1: Thống kê tạo ra từ diển, ghi vào tệp nén, t:=false
Trang 15Bước 3: Code(ch), Dừng chương trình
Thuật toán giải nén:
Bước 1: Đọc thông tin từ điển ở trong tệp nén, đọc byte tiếp theo và giải
Trang 16For i:=1 to length(s) do
Bước 3: Decode(b,s,t); ghi s ra tệp giải nén Dừng chương trình
Đánh giá: Thuật toán LZW đã khắc phục được sự lãng phí về bộ nhớ mà các
thuật toán trước không tận dụng được hết Thuật toán có thời gian chạy chương trình nhanh nếu chúng ta sử dụng cấu trúc cây( nhị phân, tam phân) Một trong những ưu điểm nữa là thuật toán có hiệu quả nén cao
1.2.4 Ph ươ ng pháp mã hóa s ố h ọ c (Arithmetic Coding)
Phương pháp này giống với mã hóa Huffman ở chỗ nó cũng dựa trên bảng chữ cái và tần số xuất hiện của từng chữ, nó cũng có thể áp dụng dạng
động hoặc dạng tĩnh dựa vào việc thay đổi các khoảng tần số trong quá trình
mã hóa
Trang 17Mục đích của phương pháp là tìm ra một khoảng duy nhất thể hiện một chuỗi ký tự có độ dài cố định, tiếp theo cần chọn trong khoảng này một số thập phân thích hợp, và coi đấy là mã biểu diễn cho chuỗi ký tự trên Quá trình mã hóa được khởi tạo với khoảng ban đầu là [0, 1)
Trang 18Sau khi đã chia được các khoảng cho mỗi ký tự đơn, tiếp tục chia các khoảng của bước trước cho 2 ký tự ghép Cụ thể là khoảng [0, 1/ 4) của A
được chia thành hai khoảng cho AA, AB dựa vào tần số xuất hiện của chúng
Thực hiện chia khoảng cho BA, BB dựa vào khoảng chia cho B tương tự
Thuật toán tổng quát:
mảnh thể hiện của n ký tự:
Đầu vào của quá trình giải mã là một phân số thập phân, và đầu ra là
một chuỗi ký tự, quá trình mã hóa và giải mã đối với thuật toán này là tương
đồng
Thuật toán được áp dụng hiệu quả đối với những bảng chữ cái nhỏ, nó
có ứng dụng cao chỉ sau mã hóa Huffman Thuật toán QM áp dụng cho ảnh, PPM áp dụng cho văn bản, đều dựa trên nền của phương pháp số học dưới dạng động Thuật toán PPM quan tâm tới những chuỗi ký tự có tần số xuất hiện cao để ưu tiên mã hóa ít tốn kém bộ nhớ nhất Với mỗi ký tự là đầu vào của thuật toán, chuơng trình tiến hành phân tích sự xuất hiện của ký tự này trong các chuỗi đã được mã hóa ở các bước trước nhằm tìm ra chuỗi có tần số xuất hiện cao chứa ký tự vừa đọc Khi thực hiện chia khoảng [0, 1), chọn giá trị biểu diễn của một chuỗi ký tự, sử dụng các thông tin về tần số xuất hiện để tiến hành ưu tiên đúng đối tượng
1.2.5 Mã hóa ki ể u t ừ đ i ể n
Kỹ thuật này đã được 1 bài báo xuất bản vào năm 1967 khẳng định:
"Phương pháp nén tốt nhất có thể đạt được đó là việc thay thế các xâu ký
tự thường xuyên lặp đi, lặp lại nhiều lần bằng chỉ số mà nó đã xảy ra trong quá khứ" Phương pháp thay một đoạn ký tự bằng vị trí một đoạn
Trang 19giống hệt nó trong quá khứ được gọi là Ziv - Lempel do 2 nhà bác học Jacob Zib và Abraham Lempel phát triển năm 1977 Như vậy ta có:
Kỹ thuật từ điển là kỹ thuật sử dụng phương pháp phân đoạn văn bản thành các đoạn nhỏ hơn sao cho nó đạt được độ dài nhất có thể được
mà nó đã xuất hiện ở trong quá khứ
Định nghĩa (phân đoạn văn bản)
Phân đoạn văn bản A là chia nó ra thành các đoạn nhỏ hơn Mỗi
đoạn được gọi là một phân đoạn
đoạn văn bản có độ dài lớn nhất mà sao cho khi đi tìm trong quá khứ thì
Trong kỹ thuật từ điển, tương tự như kỹ thuật thống kê, ta cũng có hai phương án sau:
Một số những nhược điểm của từ điển tĩnh:
+ Kích thước của từ điển tĩnh không thể mở rộng ra, để cập nhật các thông tin mới so với các loại dữ liệu khác
+ Quá trình nghiên cứu thiết kế từ điển đòi hỏi nhiều công sức + Các thuật toán sử dụng từ điển tĩnh chạy tương đối chậm
+ Tốn không gian lưu trữ dữ liệu
Trang 20Tuy nhiên bên cạnh những nhược điểm này thì từ điển tĩnh cũng có ưu
điểm là: Thiết kế các thuật toán áp dụng cho việc tìm kiếm trên từ điển
tĩnh đơn giản tốn ít thời gian
Do những đặc tính hạn chế của từ điển tĩnh, kết hợp với những đặc
điểm nổi bật của thuật toán nén là "sự cứng nhắc" đã làm cho người dùng
chương trình để tiết kiệm bộ nhớ nhàm chán không thích sử dụng các chương trình nén nữa Vậy phải có cách để khắc phục những hạn chế đó
và làm cho chương trình nén dữ liệu trở nên mềm dẻo hơn Chính vì vậy những thuật toán nén chỉ đạt hiệu quả cao nếu chúng ta xử lý tốt "từ điển"
được sử dụng trong các thuật toán nói chung
Những đặc điểm chính của từ điển động:
+ Kích thước của từ điển có thể thay đổi tuỳ theo kích thước của tập tin
+ Không tốn thời gian lưu trữ từ điển
+ Thời gian thực hiên quá trình nén nhanh
+ Từ điển không phụ thuộc vào kiểu dữ liệu
+ Thời gian thực hiện quá trình giải nén chậm
Với từ điển động thì không những làm cho thuật toán nén đạt hiệu quả cao hơn, khắc phục được sự cứng nhắc của thuật toán nén, góp phần làm cho thuật toán trở nên mềm dẻo hơn Nhưng kích thước cảu từ điển tăng lên rất nhanh khi các tập tin đem nén mà độ dư thừa của chúng
Trang 21không cao Vậy để tăng kích thước của từ điển và không làm cho chúng lớn quá mức bộ nhớ mà máy tính có thì chúng ta phải thực hiện xử lý từ
điển sao cho lượng thông tin mà từ điển đó đem lại nén đạt hiệu quả cao
và cải thiện sự cứng nhắc của thuật toán nén Như chúng ta đều biết, việc nén dữ liệu chẳng qua là việc mã các thông tin thương xuyên xuất hiện bằng một từ mã ngắn và thông tin ít xuất hiện bằng từ mã dài và được lưu trữ trong một từ điển Vậy chúng ta có một số phương án sau:
+ Sử dụng loại mã có chiều dài cố định:
Trong phương án này, số bits cần nén dữ liệu cần được quyết định trước khi tiến hành nén Nén sử dụng số bits ít thì từ điển sẽ nhanh chóng
bị đầy do đó hiệu quả nén không cao Ngược lại nếu chúng ta sử dụng số bits quá lớn thì sẽ gây lãng phí và cũng dẫn đến không có hiệu quả cao trong việc nén
+ Sử dụng loại mã có chiều dài thay đổi:
Phương án này nảy sinh một vấn đễ là chiều dài mã là bao nhiêu hay nói cách khác đó là kích thước của mảng làm từ điển có phạm vi bao nhiêu là phù hợp? Nếu kích thước của từ điển nhỏ thì có ưu điểm trong việc tìm kiếm trên từ điển vì vậy thuật toán chạy nhanh khắc phục được một hạn chế của thuật toán nén là thời gian Ngược lại nếu chúng ta sử dụng một từ điển có kích thước lớn thì làm cho thuật toán chạy chậm Do vậy chúng ta phải tìm ra kích thước của từ điển sao cho phù hợp để đảm bảo thời gian thực hiện chương trình không quá lâu mà vẫn đạt hiệu quả nén cao Để đạt được những yêu cầu trên người ta sử dụng loại mã có chiều dài thay đổi từ 8 đến 13 bit Có nghĩa là khi bộ nén dùng hết mã 8 bits thì nó sẽ dùng mã 9 bits, 10 bits, Tuy nhiên nếu dùng hết số bits cho phép mà nguồn thông tin vẫn còn thì chúng ta lại có cách giải quyết sau:
* Dừng quá trình thêm các đoạn mới vào từ điển, tiến hành xoá từ
điển hiện tại và bắt đầu xây dựng lại từ điển cho dữ liệu mới Theo cách
Trang 22nói trên thì phương pháp nén khá mềm dẻo nhưng hiệu quả nén lại không cao do chúng ta không tận dụng được thông tin trên từ điển cũ
Tóm lại, mã có từ điển cố định được gọi là mã tĩnh và ngược lại nếu
từ điển biến đổi thì ta gọi đó là mã động
Để tiến hành nén theo kỹ thuật từ điển ta có thuật toán phân đoạn Đây chính là tiền đề cho hệ thống mã thuộc họ LZ Thuật toán phân đoạn
bao gồm 3 giai đoạn sau:
+ Bước 1: Phân đoạn văn bản theo một nguyên lý nào đó
+ Bước 2: Mã hoá các đoạn văn bản đó
Trang 23Chương 2: NGHIÊN CỨU KỸ THUẬT NÉN VĂN BẢN TIẾNG VIỆT SỬ DỤNG KỸ THUẬT MÃ HÓA SỐ HỌC 2.1 Các bảng mã tiếng Việt
2.1.1 Chu ẩ n l ư u tr ữ Unicode
Unicode (hay gọi là mã thống nhất; mã đơn nhất) là bộ mã chuẩn quốc
tế được thiết kế để dùng làm bộ mã duy nhất cho tất cả các ngôn ngữ khác nhau trên thế giới, kể cả các ngôn ngữ sử dụng ký tự tượng hình phức tạp như tiếng Trung Quốc, tiếng Thái,.v.v Vì những điểm ưu việt đó, Unicode đã
và đang từng bước thay thế các bộ mã truyền thống, kể cả bộ mã tiêu chuẩn ISO 8859 và hiện đang được hỗ trợ trên rất nhiều phần mềm cũng như các trình ứng dụng, chẳng hạn Windows
2.1.1.1.Kho chữ
Unicode chiếm trước 1.114.112 (= 220+216) mã chữ, và hiện nay đã gán ký hiệu cho hơn 96000 mã chữ 256 mã đầu tiên phù hợp với ISO 8859-1,
là cách mã hóa ký tự phổ biến nhất trong "thế giới phương Tây"; do đó, 128
ký tự đầu tiên còn được định danh theo ASCII
Không gian mã Unicode cho các ký tự được chia thành 17 mặt phẳng (plane) và mỗi mặt phẳng có 65536 code point Mặt phẳng đầu tiên (plane 0),
"Mặt phẳng đa ngôn ngữ căn bản" (Basic Multilingual Plane - BMP), là nơi
mà đa số các ký hiệu được gán mã BMP chứa các ký hiệu cho hầu hết các ngôn ngữ hiện đại, và một số lượng lớn các ký tự đặc biệt Đa số các code point được phân bố trong BMP được dùng để mã hóa các ngôn ngữ CJKV (Hán-Nhật-Hàn-Việt)
Hai mặt phẳng tiếp theo được dùng cho các ký tự "đồ họa" Mặt phẳng 1, "Mặt phẳng đa ngôn ngữ bổ sung" (Supplementary Multilingual Plane - SMP), được dùng chủ yếu cho các loại chữ viết cổ, ví dụ Egyptian hieroglyph (chưa được mã hóa), nhưng cũng còn được dùng cho các ký hiệu
Trang 24âm nhạc Mặt phẳng 2, (Supplementary Ideographic Plane - SIP), được dùng cho khoảng 40000 chữ Trung Quốc ít gặp mà đa số là các ký hiệu cổ, ngoài ra cũng có một số ký hiệu hiện đại Mặt phẳng 14 hiện chứa một số các ký tự thẻ ngôn ngữ không được khuyến khích và một số ký hiệu lựa chọn biến thể Mặt phẳng 15 và Mặt phẳng 16 được mở cho các sử dụng cá nhân
Vẫn còn nhiều tranh luận giữa các chuyên gia về ngôn ngữ CJK Nhật-Hàn), đặc biệt là các chuyên gia người Nhật, về nhu cầu và lợi ích kỹ thuật của việc "thống nhất chữ Hoa", tức là việc chuyển những bộ chữ Hoa và chữ Nhật vào trong một bộ chữ hợp nhất (Xem thêm mã hóa chữ Hoa)
(Hoa-Kho ≈220 điểm mã bảo đảm sự tương thích với bộ mã UTF-16 Việc mới chỉ dùng hết có 10% kho chữ cho thấy rằng kho chữ cỡ ≈20 bit này khó
bị đầy trong một tương lai gần
2.1.1.2 Bảng mã
Unicode là một cách để đánh số duy nhất cho tất cả các ký tự được dùng bởi con người trong ngôn ngữ viết Nhưng những con số đó được ghi trong các hệ thống xử lý văn bản lại là những vấn đề khác; những vấn đề đó là hậu quả của việc phần lớn các phần mềm ở phương Tây chỉ biết tới các hệ thống mã hóa 8-bit, và việc đưa Unicode vào các phần mềm chỉ mới diễn ra chậm chạp trong những năm gần đây
Các chương trình 8-bit cũ chỉ nhận biết các ký tự 8 bit, và không thể dùng nhiều hơn 256 điểm mã nếu không có những cách giải quyết đặc biệt
Do đó người ta phải đề ra nhiều cơ chế để dùng Unicode; tùy thuộc vào khả năng lưu trữ, sự tương thích với chương trình nguồn và sự tương tác với các
hệ thống khác mà mỗi người chọn một cơ chế
UTF-32
Trang 25Cách đơn giản nhất để lưu trữ tất cả các 220+216 Unicode code points
là sử dụng 32 bit cho mỗi ký tự, nghĩa là, 4 byte – do đó, cách mã hóa này
được Unicode gọi là UTF-32 và ISO/IEC 10646 gọi là UCS-4 Vấn đề chính
của cách này là nó hao chỗ hơn 4 lần so với trước kia, do đó nó ít được dùng trong các vật nhớ ngoài (như đĩa, băng) Tuy nhiên, nó rất đơn giản, nên một
số chương trình sẽ sử dụng mã hóa 32 bit bên trong khi xử lý Unicode
UTF-16
UTF-16 là một cách mã hóa dùng Unicode 20 bit Các ký tự trong BMP được diễn tả bằng cách dùng giá trị 16-bit của code point trong Unicode CCS Có hai cách để viết giá trị 16 bit trong một dòng (stream) 8-bit Có lẽ bạn đã nghe qua chữ endian Big Endian có nghĩa là cho Most Significant Byte đi trước, tức là nằm bên trái – do đó ta có UTF-16BE Còn Little Endian thì ngược lại, tức là Least Significant Byte đi trước – do đó ta có UTF-16LE Thí dụ, giá trị 16-bit của con số Hex1234 được viết là Hex12 Hex34 trong Big Endian và Hex34 Hex12 trong Little Endian
Những ký hiệu không nằm trong BMP được biểu diễn bằng cách dùng surrogate pair (cặp thay thế) Code points có giá trị từ U+D800 đến U+DFFF được dành riêng ra để dùng cho mục đích này Trước hết, một code point có 20 bit được phân ra làm hai nhóm 10 bit Nhóm Most Significant 10 bit được map vào một giá trị 10 bit nằm trong khoảng từ u+D800 đến u+DBFF Nhóm Least Significant 10 bit được map vào một giá trị 10 bit nằm trong khoảng từ U+DC00 đến U+DFFF Theo cách đó UTF-16 có thể biểu diễn được những ký hiệu Unicode có 20 bit
Trang 26UTF-8
UTF-8 là một cách mã hóa để có tác dụng giống như UCS-4 (cũng là UTF-16), chứ không phải có code point nào khác UTF-8 được thiết kế để tương thích với chuẩn ASCII UTF-8 có thể sử dụng từ một (cho những ký tự trong ASCII) cho đến 6 byte để biểu diễn một ký tự
Chính vì tương thích với ASCII, UTF-8 cực kỳ có lợi thế khi được sử dụng để bổ sung hỗ trợ Unicode cho các phần mềm có sẵn Thêm vào đó, các nhà phát triển phần mềm vẫn có thể sử dụng các hàm thư viện có sẵn của ngôn ngữ lập trình C để so sánh (comparisons) và xếp thứ tự (Ngược lại,
để hỗ trợ các cách mã hóa 16 bit hay 32 bit như ở trên, một số lớn phần mềm
buộc phải viết lại do đó tốn rất nhiều công sức Một điểm mạnh nữa của
UTF-8 là với các văn bản chỉ có một số ít các ký tự ngoài ASCII, hay thậm chí cho các ngôn ngữ dùng bảng chữ cái Latinh như tiếng Việt, tiếng Pháp, tiếng Tây Ban Nha, v.v.; cách mã hóa kiểu này cực kỳ tiết kiệm không gian lưu trữ
UTF-8 được thiết kế đảm bảo không có chuỗi byte của ký tự nào lại nằm trong một chuỗi của ký tự khác dài hơn Điều này khiến cho việc tìm kiếm ký tự theo byte trong một văn bản là rất dễ dàng Một số dạng mã hóa khác (như Shift-JIS) không có tính chất này khiến cho việc xử lý chuỗi ký tự trở nên phức tạp hơn nhiều Mặc dù để thực hiện điều này đòi hỏi phải có độ
dư (văn bản sẽ dài thêm) nhưng những ưu điểm mà nó mang lại vẫn nhiều hơn Việc nén dữ liệu không phải là mục đích hướng tới của Unicode và việc này cần được tiến hành một cách độc lập
Các quy định chính xác của UTF-8 như sau (các số bắt đầu bằng 0x là các số biểu diễn trong hệ thập lục phân)
Các ký tự có giá trị nhỏ hơn 0x80, sử dụng 1 byte có cùng giá trị
Trang 27Các ký tự có giá trị nhỏ hơn 0x800, sử dụng 2 byte: byte thứ nhất có giá trị 0xC0 cộng với 5 bit từ thứ 7 tới 11 (7th-11th least significant bits); byte thứ hai có giá trị 0x80 cộng với các bit từ thứ 1 tới thứ 6 (1st-6th least significant bits)
Các ký tự có giá trị nhỏ hơn 0x10000, sử dụng 3 byte: byte thứ nhất
có giá trị 0xE0 cộng với 4 bit từ thứ 13 tới 16; byte thứ hai có giá trị 0x80 cộng với 6 bit từ thứ 7 tới 12; byte thứ ba có giá trị 0x80 cộng với 6 bit từ thứ
1 tới thứ 6
Các ký tự có giá trị nhỏ hơn 0x200000, sử dụng 4 byte: byte thứ nhất
có giá trị 0xF0 cộng với 3 bit từ thứ 19 tới 21; byte thứ hai có giá trị 0x80 cộng với 6 bit từ thứ 13 tới 18; byte thứ ba có giá trị 0x80 cộng với 6 bit từ thứ 7 tới thứ 12; byte thứ tư có giá trị 0x80 cộng với 6 bit từ thứ 1 tới thứ 6
Hiện nay, các giá trị khác ngoài các giá trị trên đều chưa được sử dụng Tuy nhiên, các chuỗi ký tự dài tới 6 byte có thể được dùng trong tương lai
Chuỗi 5 byte sẽ lưu trữ được mã ký tự chứa đến 26 bit: byte thứ nhất
có giá trị 0xF8 cộng với 2 bit thứ 25 và 26, các byte tiếp theo lưu giá trị 0x80 cộng với 6 bit có ý nghĩa tiếp theo
Chuỗi 6 byte sẽ lưu trữ được mã ký tự chứa đến 31 bit: byte thứ nhất
có giá trị 0xFC cộng với bit thứ 31, các byte tiếp theo lưu giá trị 0x80 cộng với 6 bit có ý nghĩa tiếp theo