You are on page 1of 8

Lab3.

SỬA LỖI TỰ ĐỘNG CHO VĂN BẢN TIẾNG VIỆT


(TS. Trần Ngọc Anh)

(1) Sửa lỗi chính tả tự động tiếng Việt.


(2) Tách các dấu trong câu tiếng Việt.
(3) Tách các âm tiết dính tiếng Việt.

1. Sửa lỗi chính tả tự động tiếng Việt


1.1. Các lỗi chính tả thường gặp:
+ Các công cụ gõ tiếng Việt có hai chế độ bỏ dấu: òa/oà, óe/oé, ủy/uỷ,..
+ Lỗi khi gõ dấu thanh không đúng vị trí: qúa, cuả, gía, tứơng, đựơc,...
+ Lỗi hai dấu thanh: trờí/trời, nguỵễn/nguyễn, tựợng/tượng,...
+ Lỗi thanh sắc với phụ âm cuối p/t/c/ch: cẳp/cắp, viềt/viết,...
+ Lỗi nguyên âm ươ (uơ/ưo): nguời/người, uớc/ước, Tưòng/Tường,...
+ Lỗi ngh/ng: nghô/ngô nghê, nghành/ngành nghề, nge/nghe ngóng,...
+ Lỗi g/gh: ghồ/gồ ghề, ghanh/ganh ghét,...
+ Lỗi vần uyêch/uêch: khuyếch/khuếch đại, rỗng tuyếch/tuếch,...
Trên cơ sở quy định về chuẩn chính tả tiếng Việt hiện hành và quy tắc đặt dấu
thanh tiếng Việt, tác giả đề xuất thuật toán 3.1 để phân tích và sửa tự động một số lỗi
chính tả tiếng Việt phổ biến.
1.2. Phương pháp sửa lỗi chính tả tự động tiếng Việt
Cấu tạo âm tiết tiếng Việt được mô tả như Hình 3.1.

Hình 3.1. Cấu tạo âm tiết tiếng Việt


Theo một số tài liệu thì có đến 5 quy tắc đặt dấu thanh cho tiếng Việt, có thể rút
gọn lại còn 2 quy tắc cơ bản như sau:
Quy tắc 1. Khi vần có một nguyên âm, dấu thanh đặt tại nguyên âm đó.
Quy tắc 2. Khi vần có từ hai nguyên âm trở lên:
+ Nếu vần đang xét về nguyên tắc có thể kết hợp (hoặc đã sẵn có) một trong số
các phụ âm: C, CH, M, N, NG, NH, P, T làm âm cuối, ta đặt dấu thanh vào
nguyên âm cuối cùng bên phải (hoàng, quyết, quyển, giường, thiếp, bước,...).
+ Nếu vần đang xét về nguyên tắc không thể kết hợp được với một trong số
các phụ âm cuối, ta đặt dấu thanh vào nguyên âm bên trái của nguyên âm
cuối cùng (hoài, hỏi, hảo, màu, múa, phía,...).
Phân tích âm tiết tiếng Việt
Theo kết quả phân tích âm tiết tiếng Việt trên máy tính thì cấu tạo âm tiết tiếng
Việt được mô tả theo cách sau:
ÂM-TIẾT = [PHỤ ÂM ĐẦU] + <ÂM GIỮA> + [PHỤ ÂM CUỐI]
với [...] là phần không bắt buộc, và <...> là bắt buộc phải có.
(i) Phụ âm đầu: có 27 dạng: B, C, CH, D, Đ, G, GH, GI, H, K, KH, L, M, N, NG,
NGH, NH, P, QU, R, S, T, TH, TR, V, X và rỗng (không có).
(ii) Âm giữa: là tổ hợp các nguyên âm tạo thành. Theo định nghĩa này, có thể chia
các âm giữa thành ba loại:
+ Âm giữa loại 1: có thể kết hợp với phụ âm cuối hoặc không để tạo vần.
Có 14 dạng: A, E, Ê, I, Y, O, Ô, Ơ, U, Ư, OA, OE, UÊ, UY.
+ Âm giữa loại 2: là những âm không thể kết hợp với phụ âm cuối. Có 33
dạng: AI, AO, AU, AY, ÂU, ÂY, EO, ÊU, IA, IU, OI, ÔI, ƠI, ƠU, UA, UI,
UƠ, ƯA, ƯI, ƯU, IÊU, OAI, OAO, OAY, OEO, UÂY, UÔI, UYA, UYU,
ƯƠI, ƯƠU, YÊU, YU.
+ Âm giữa loại 3: là bắt buộc phải kết hợp với phụ âm cuối để tạo vần. Có
10 dạng: Ă, Â, IÊ, OĂ, OO, UÂ, UÔ, UYÊ, ƯƠ, YÊ.
(iii) Phụ âm cuối: có 8 dạng: C, CH, M, N, NG, NH, P, T. Trong đó, chia thành
hai nhóm với cách đánh dấu thanh khác nhau:
+ M, N, NG, NH: các âm giữa có thể nhận đến 6 dấu thanh.
+ C, CH, P, T: các âm giữa chỉ có thể nhận thanh sắc và nặng.
Quy tắc đánh dấu thanh như sau:
- Vị trí đặt dấu thanh: theo nguyên tắc đặt tại âm chính, được xác định:
+ Với âm giữa loại 1/3: đặt dấu thanh tại vị trí nguyên âm cuối.
A, E, Ê, I, Y, O, Ô, Ơ, U, Ư, OA, OE, UÊ, UY.
Ă, Â, IÊ, OĂ, OO, UÂ, UÔ, UYÊ, ƯƠ, YÊ.
+ Với âm giữa loại 2: đặt vào vị trí bên trái của nguyên âm cuối.
AI, AO, AU, AY, ÂU, ÂY, EO, ÊU, IA, IU, OI, ÔI, ƠI, ƠU,
UA, UI, UƠ, ƯA, ƯI, ƯU, IÊU, OAI, OAO, OAY, OEO,
UÂY, UÔI, UYA, UYU, ƯƠI, ƯƠU, YÊU, YU.
- Với âm tiết có phụ âm cuối: C, CH, P, T thì chỉ đặt thanh sắc/nặng.
Thuật toán 3.1. Thuật toán sửa lỗi chính tả dấu thanh tự động.
+ Đầu vào: inpT là văn bản tiếng Việt
+ Đầu ra : outT là văn bản tiếng Việt đã sửa lỗi dấu thanh

Bước 1. Tách văn bản inpT thành mảng các đơn vị ati (bằng dấu cách).
Bước 2. Nếu ati chứa nguyên âm có dấu, và ati  từ điển âm tiết (lỗi) thì
tách ra 4 phần: dấu thanh, phụ âm đầu, âm giữa và phụ âm cuối.
Bước 3. Tạo lại âm tiết ati mới với các thông tin cũ (gồm có phụ âm đầu,
âm giữa và phụ âm cuối) với dấu thanh đặt theo quy tắc đã nêu.
Bước 4. Ghép mảng các đơn vị ati lại thành văn bản mới outT.
Độ phức tạp thuật toán là O(n), với n là số lượng âm tiết trong văn bản.
2. Tách các dấu trong câu
Đây là một trong những nhiệm vụ tiền xử lý văn bản tiếng Việt. Do có sự nhập
nhằng giữa việc tách hay không tách một số dấu câu khi đi kèm với âm tiết, chữ viết
tắt, số,... Hơn nữa, các dấu câu chiếm tỉ lệ khá lớn trong văn bản (14.34 - 15.02%) nên
cần phải được phân tách đúng.
Trước hết, sử dụng dấu cách để tách câu đầu vào thành một mảng các đơn vị âm
tiết ai. Với mỗi đơn vị âm tiết ai đó, tách theo 3 trường hợp như sau (Hình 3.2):
+ Kí tự đặc biệt (kt) ở bên trái âm tiết (amtiet) ai, có dạng: (kt)(amtiet)
+ Kí tự đặc biệt ở bên phải ai, có dạng: (amtiet)(kt)
+ Kí tự đặc biệt ở giữa của ai, có dạng: (am)(kt)(tiet)
Thuật toán 3.2. Tách kí tự đặc biệt dựa vào cây quyết định nhị phân.

Hình 3.2. Cây quyết định nhị phân để tách các kí tự đặc biệt
Kí tự dấu câu: _ | ` ^ ~ ! @ # $ % & * ( ) - + = { } [ ] < > \ / ; : . , .. " ... '
- Thay các kí tự "|" và "_" bằng dấu cách.
- Cắt bỏ các dấu cách thừa, chỉ để lại 1 dấu cách.
- Tách dấu câu: | ... | .. | . | ? | ! | : | ; | , | ( | ) | { | } | [ | ] | < | > | " | ~ | ` |
- Không tách dấu nháy đơn (') vì phải dùng như: T'rưng, K'Ho, it's
- Không tách dấu chấm (.) sau chữ viết tắt: | Q. |, | TP. |, | TS. |, | Th. |,...
- Một số kí tự đặc biệt { - & % $ ^ # * + . } được xử lý riêng:
+ Kí tự "-" giữa 2 kí tự kề nhau, trước chữ in thường: không tách.
Ví dụ: | a-xit |, | Lê-nin |, | bê-tông |,...
+ Nếu có 1 dấu cách, hoặc dấu "-" trước âm tiết viết Hoa thì tách.
Ví dụ: Mác-Lê-nin : có 1 đơn vị âm tiết: Mác-Lê-nin
Thừa Thiên-Huế : có 2 đơn vị âm tiết: Thừa, Thiên-Huế
Cần tách ra: Mác - Lê-nin, Thừa Thiên - Huế, Bà Rịa - Vũng Tàu
Các trường hợp khác đi kèm với 1 dấu cách thì tách ra, chẳng hạn:
Mác– Lê-nin, Mác –Lê-nin => Mác – Lê-nin
+ Với các kí tự &, %, $, # thì tách ra khi đứng trước/sau kí tự
GD&ĐT, GD& ĐT, GD &ĐT => GD & ĐT
Tỉ lệ% => Tỉ lệ %, 45% => 45 %, 25$ => 25 $, dấu# => dấu #
+ Không tách dấu {# + - .} đứng trước số: #65, .5, -6, +20,...
Ngoài các kí tự dấu câu đã nêu, có thể sẽ gặp các kí tự unicode đặc biệt khác
như:  , ,... và các kí tự nước ngoài thì ta sẽ thực hiện tách ra.
3. Tách các từ dính tiếng Việt
Đây là một trong những nhiệm vụ tiền xử lý văn bản tiếng Việt. Hầu hết các văn
bản được lấy tự động về từ Internet (website), có nhiều trường hợp các âm tiết tại biên
phải trên Web khi căn lề Justify thường bị dính với nhau. Chẳng hạn như "vănbản",
"hoàbình", "hànội", "cácâm",... Do vậy trước khi xử lý, cần phải tách ra cho đúng.
Đặc điểm này tương tự như trong tiếng Trung, Lào, Khmer,... có các con chữ viết liền
nhau, cần phải tách ra cho đúng mới xử lý được.
Tổng quát, xét ví dụ gồm dãy âm tiết bị dính:
Táchcáctừdính
Yêu cầu tách ra cho đúng như sau:
Tách các từ dính
Cách giải quyết:
- Cần xác định vị trí để ngắt các âm tiết ra (chèn dấu cách - space): Dùng so khớp
cực đại dựa vào từ điển âm tiết tiếng Việt để tách.
+ Xác định cửa sổ âm tiết cực đại là 7 (chữ "nghiêng" trong từ điển)
+ Duyệt từ trái sang phải hay ngược lại để tìm các ứng viên theo cửa sổ.
- Khi có từ 02 phương án tách trở lên ta gọi là nhập nhằng ranh giới. Chẳng hạn:
"hànội" => "hàn ội" / "hà nội", "cácâm" => "các âm" / "cá câm". Ta có thể dùng mô
hình n-gram mức ký tự hay mức âm tiết học từ kho ngữ liệu để tách.
Với mô hình n-gram mức âm tiết được học từ kho ngữ liệu thô âm tiết tiếng Việt,
ta sẽ có các xác suất bigram như sau:
P(nội | hà) >> P(ội | hàn) => chọn phương án tách "hà nội"
P(âm | các) >> P(cá | câm) => chọn phương án tách "các âm"
Thuật toán tổng quát tách từ dính: theo 2 bước chính sau:
Bước 1. Sinh các ứng viên dựa vào từ điển âm tiết tiếng Việt.
(Gán điểm cho các ứng viên theo nhập nhằng và ngữ cảnh).
Bước 2. Tìm dãy tách âm tiết tối ưu.
3.1. Sinh các ứng viên dựa vào từ điển âm tiết tiếng Việt
Bước này sinh ra mạng từ tiếng Việt dựa vào so khớp cực đại theo từ điển từ
vựng. Việc sinh các ứng viên từ hay tìm dãy tách từ tối ưu có thời gian phụ thuộc cửa
sổ ký tự. Trong tiếng Việt, các âm tiết có độ dài từ 1 đến 7 ký tự. Do vậy, việc chọn
cửa sổ 7 âm tiết đảm bảo yêu cầu về độ chính xác, thuật toán thực hiện nhanh và tiết
kiệm bộ nhớ.
Dùng một mảng hai chiều score[1..n, 1..7] (như một mạng ký tự) để ghi điểm cho
mỗi ứng viên aij theo cửa sổ 7 ký tự (1 ≤ i ≤ n, 1 ≤ j ≤ 7). Nếu một dãy ký tự (ci...ci-1+j)
có thể là một âm tiết (aij) trong từ điển hay ngữ liệu huấn luyện hay theo quy tắc ngôn
ngữ học thì ghi điểm cho nó bằng 1 hoặc tỉ lệ ngịch với số lượng ký tự của âm tiết,
ngược lại là +∞ như sau:

 1 nếu aij  Từđiển


score[i, j] =  (3.1)
  nếu aij  Từđiển
(1 ≤ i ≤ n, 1 ≤ j ≤ 7)

Minh hoạ sinh ứng viên mạng từ bằng đồ thị: với 2 câu ví dụ mẫu như sau:
 Dãy 1. "Táchcáctừdính"
 Dãy 2. "dínhcácâmtiết"
Biểu diễn đồ thị của mảng điểm số cho hai câu trên như hình 3.3 và 3.4.

7       
6        
5         
4          
3           
2            
1              
Cửa sổ 1 2 3 4 5 6 7 8 9 10 11 12 13 14
Dãy 1 T á c h c á c t ừ d í n h
Hình 3.3. Minh hoạ sơ đồ mạng từ được sinh theo từ điển cho Dãy 1
7       
6        
5         
4          
3           
2            
1              
Cửa sổ 1 2 3 4 5 6 7 8 9 10 11 12 13 14
Dãy 2 d í n h c á c â m t í ế t
Hình 3.4. Minh hoạ sơ đồ mạng từ được sinh theo từ điển cho Dãy 2
Trên đồ thị Hình 3.3, các đường liền nét (mũi tên đỏ) mô tả các âm tiết thuộc từ
điển có điểm số ở trên cạnh (mũi tên xanh) ra (≤1), ngược lại, các đường đứt nét
(màu xanh) mô tả không phải âm tiết với điểm số bằng +∞. Với mô tả đồ thị như vậy,
bài toán tách từ dính trở thành bài toán tìm đường đi ngắn nhất trên đồ thị có hướng.
(i) Dãy 1 có n = 13 ký tự, mạng ký tự được sinh theo từ điển như Hình 3.3.
Trường hợp này, chỉ có 1 phương án với tổng điểm số nhỏ nhất là 6:
(1) => (4) | (5) => (7) | (8) => (9) | (10) => (13) | (14)
Kết quả tách: Tách các từ dính
(ii) Dãy 2 có n = 13 ký tự, mạng ký tự được sinh theo từ điển như Hình 3.4.
Trường hợp này, có hai phương án có điểm số bằng nhau và bằng 6:
+ Phương án 1: (1) => (4) | (5) => (7) | (8) => (9) | (10) => (13) | (14)
Kết quả: dính các âm tiết
+ Phương án 2: (1) => (4) | (5) => (6) | (7) => (9) | (10) => (13) | (14)
Kết quả: dính cá câm tiết
Đây là trường hợp nhập nhằng chồng lấp ký tự c: (là ký tự cuối của âm tiết
trước hoặc là ký tự đầu của âm tiết sau) khi điểm số bằng nhau. Nhập nhằng này
có thể được giải quyết bằng n-gram mức âm tiết.
Thuật toán 3.3. Sinh ứng viên có cửa sổ ký tự dựa vào từ điển âm tiết.
+ Đầu vào: dãy n ký tự: a1, a2, a3, ..., an.
+ Đầu ra : mảng điểm số (mạng ký tự): score[1..n, 1..7]
B1. Lặp với mỗi ký tự ci (1 ≤ i ≤ n) {
1) Điểm số ký tự ci (j = 1): score[i, 1]  1; //ký tự luôn tồn tại.
2) Lặp với 6 ký tự kế tiếp ci: 2 ≤ j ≤ 7, (i + 1 ≤ i + j - 1 ≤ i + 6) {
a) Nếu (aij = (ci...ci+j-1)  Từđiển) thì: score[i, j]  1;
ngượclại thì score[i, j]  +;
}//kết thúc vòng lặp cửa sổ con 6 ký tự
} //kết thúc vòng lặp n ký tự.
B2. Trả về score; // trả về mảng điểm số của mạng ký tự.
Độ phức tạp thuật toán: Có 2 vòng lặp lồng nhau và lồng với việc tìm kiếm âm
tiết trong từ điển: B1) lặp n lần, 1) và 2) thực hiện 7 lần, a) tìm kiếm âm tiết dùng
Automat tối thiểu (MinDFA) với thời gian là O(1). Vì vậy, thuật toán 3.3 có độ phức
tạp tổng hợp là O(n), với n là số ký tự trong dãy vào.
3.2. Tìm dãy tách từ dính tối ưu
Trên cơ sở điểm số của mỗi âm tiết trong mạng: score[1..n, 1..7], ta sẽ tìm đường
đi ngắn nhất (có tổng số điểm nhỏ nhất) từ nút 1 đến nút n trên đồ thị có hướng như
mô tả trong Hình 3.3 và 3.4. Theo so khớp cực đại, số lượng m âm tiết được tách là tối
thiểu. Mỗi âm tiết có một điểm số tối đa là 1, vì thế tổng điểm số của chúng là nhỏ
nhất (≤ m). Đây là hàm mục tiêu để xác định dãy âm tiết tối ưu trong mạng ký tự theo
điểm số score[i, j].
Gọi SC(S(m)) là tổng điểm số theo phương án tách m âm tiết của dãy S. Vì thế,
phương án tối ưu thoả mãn tiêu chuẩn sau:
m 
min{SC ( S ( m ) )}  min  score(ai ) (3.2)
m m
 i 1 
Trong đó, ai là âm tiết thứ i được tách, m là số lượng âm tiết được tách của S.
Từ mảng điểm số score[1..n, 1..7] và phương án tối ưu theo (3.2), tác giả đưa ra
thuật toán quy hoạch động tìm kiếm dãy âm tiết được tách tối ưu như sau:
Thuật toán 3.4. Tìm dãy tách âm tiết tối ưu.
+ Đầu vào: dãy n ký tự (c1, c2, c3, ..., cn) và mảng điểm: score[1..n,1..7]
+ Đầu ra : dãy âm tiết được tách tối ưu: SegOut.
B1. SC[0]  0; //mảng SC có n+1 phần từ bắt đầu từ 0.
B2. Lặp với mỗi i trong dãy ký tự (1 ≤ i ≤ n) {
21) SC[i]  +;
22) Lặp với mỗi j từ 7 xuống 1 (j = 7 .. 1) { // cửa sổ 7 ký tự
a) Nếu (i ≥ j) thì {
a1) a  c[i – j+1]; // ký tự đầu tiên của âm tiết
a2) Nếu (SC[i] > SC[i - j] + score[i – j+1, j]) thì { // tìm SC min
a21) SC[i]  SC[i - j] + score[i – j+1, j];
a22) Lặp với các ký tự k từ vị trí (i – j+2) đến (i) {
i) a  a & c[k]; //lấy âm tiết
} //kết thúc vòng lặp a22)
} //kết thúc a2)
a3) q[i]  a; // lưu vết kết quả tách âm tiết tối ưu
} // kết thúc a)
} // kết thúc vòng lặp 22 (7 ký tự)
} // kết thúc vòng lặp B2 (n ký tự)
B3. Truy vết ngược tìm dãy âm tiết được tách từ cuối n về đầu 1, (i = n .. 1)
31) i  n;
32) SegOut  "";
33) Lặp {
b1) demKT  len(q[i]); // đếm số ký tự của âm tiết tại q[i]
b2) SegOut  q[i] & " " & SegOut; // dấu cách " " để tách âm tiết
b3) i  i – demKT;
}ChoĐếnKhi (i < 1); //kết thúc vòng lặp 33.
B4. Trả về SegOut; // trả về dãy âm tiết được tách
Độ phức tạp của thuật toán:
Tại B1, cần thời gian thực hiện là O(n); Tại B2, có 3 vòng lặp lồng nhau: vòng
21 với n lần lặp, vòng lặp 22 với 7 lần lặp, và vòng lặp a22 với 6 lần lặp. Vì vậy, thời
gian thực hiện bước B2 là O(n); Tại bước B3: có 1 vòng lặp 33 duyệt các ký tự của
mỗi âm tiết trong dãy kết quả lưu vết q[i] với tổng số ký tự là n, nên cần thời gian thực
hiện là O(n). Như vậy, thuật toán 3.4 tìm dãy tách âm tiết tối ưu cần thời gian thực
hiện là O(n), với n là số ký tự của dãy vào.
3.3. Thử nghiệm tách từ dính với các kho ngữ liệu mẫu
Sự kết hợp thuật toán 3.3 sinh ứng viên dựa vào từ điển âm tiết và thuật toán 3.4
tìm dãy tách âm tiết tối ưu tạo thành thuật toán so khớp cực đại tách từ dính tiếng Việt.
Hai thuật toán 3.3 và 3.4. đều có độ phức tạp O(n), nên thuật toán kết hợp tách từ
dính AMM (thuật toán 3.3 và 3.4) cũng có độ phức tạp O(n).
Thực hiện thử nghiệm bằng cách dùng từ điển 7015 âm tiết tiếng Việt và:
+ Tạo kho ngữ liệu dính âm tiết là charVnCorpus từ kho ngữ liệu thô tiếng Việt
rawVnCorpus bằng cách loại bỏ tất cả dấu cách cho từng câu (dòng).
+ Tách âm tiết trên kho ngữ liệu charVnCorpus bằng thuật toán AMM, n-gram
+ Đánh giá kết quả thử nghiệm:
Kí hiệu: + Nm: là số đơn vị âm tiết trong văn bản mẫu (rawVnCorpus).
+ Nt : là số đơn vị âm tiết trong văn bản kết quả tách.
+ Nđ: là số đơn vị âm tiết tách đúng so với mẫu.
+ Độ hồi tưởng R (Recall) : R = Nđ/Nm (3.3)
+ Độ chính xác P (Precision) : P = Nđ/Nt (3.4)
+ Độ đo F1-score : F1 = 2RP/(R+P) (3.5)
Bảng 3.1. Thử nghiệm tách âm tiết với thuật toán AMM và ngram
Model Nm Nt Nđ R(%) P(%) F1(%)
AMM
AMM & ngram

You might also like