ptdat commited on
Commit
9d59e02
·
verified ·
1 Parent(s): f0f8ac4

Upload tokenization_vnsabsa.py

Browse files
Files changed (1) hide show
  1. tokenization_vnsabsa.py +497 -0
tokenization_vnsabsa.py ADDED
@@ -0,0 +1,497 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from typing import Dict
3
+ from transformers import PreTrainedTokenizer
4
+ from tokenizers.implementations import CharBPETokenizer
5
+ from tokenizers.processors import TemplateProcessing
6
+ import regex as re
7
+
8
+ from typing import Tuple, Optional
9
+ import shutil
10
+ import os
11
+
12
+ class VnSmartphoneAbsaTokenizer(PreTrainedTokenizer):
13
+ def __init__(
14
+ self,
15
+ vocab_file,
16
+ merge_file,
17
+ bos_token="<s>",
18
+ eos_token="</s>",
19
+ sep_token="</s>",
20
+ cls_token="<s>",
21
+ unk_token="<unk>",
22
+ pad_token="<pad>",
23
+ mask_token="<mask>",
24
+ **kwargs
25
+ ):
26
+ self.vocab_file = vocab_file
27
+ self.merge_file = merge_file
28
+
29
+ self.tokenizer = CharBPETokenizer(vocab_file, merge_file, lowercase=True, bert_normalizer=False, split_on_whitespace_only=True)
30
+ self.tokenizer.post_processor = TemplateProcessing(
31
+ single="<s> $9 </s>",
32
+ pair="<s> $A </s> $B:1 </s>:1",
33
+ special_tokens=[
34
+ ("<s>", 2),
35
+ ("</s>", 3)
36
+ ]
37
+ )
38
+ self.tokenizer.enable_padding(pad_token="<pad>")
39
+
40
+ self.encoder = self.tokenizer.get_vocab()
41
+ self.decoder = {v: k for k, v in self.encoder.items()}
42
+
43
+ self.prepare_preprocess()
44
+
45
+ super().__init__(
46
+ bos_token=bos_token,
47
+ eos_token=eos_token,
48
+ sep_token=sep_token,
49
+ cls_token=cls_token,
50
+ unk_token=unk_token,
51
+ pad_token=pad_token,
52
+ mask_token=mask_token,
53
+ **kwargs
54
+ )
55
+
56
+ def _tokenize(self, text: str):
57
+ text = self.normalize(text)
58
+ return self.tokenizer.encode(text).tokens
59
+
60
+ def get_vocab(self) -> Dict[str, int]:
61
+ return self.tokenizer.get_vocab()
62
+
63
+ @property
64
+ def vocab_size(self):
65
+ return self.tokenizer.get_vocab_size()
66
+
67
+ def save_vocabulary(self, save_directory: str, filename_prefix: Optional[str] = None) -> Tuple[str]:
68
+ if not os.path.isdir(save_directory):
69
+ return
70
+ out_vocab_file = os.path.join(
71
+ save_directory, (filename_prefix + "-" if filename_prefix else "") + "vocab.txt"
72
+ )
73
+ out_merge_file = os.path.join(
74
+ save_directory, (filename_prefix + "-" if filename_prefix else "") + "merge.txt"
75
+ )
76
+
77
+ if os.path.abspath(self.vocab_file) != os.path.abspath(out_vocab_file) and os.path.isfile(self.vocab_file):
78
+ shutil.copyfile(self.vocab_file, out_vocab_file)
79
+ elif not os.path.isfile(self.vocab_file):
80
+ with open(out_vocab_file, "wb") as fi:
81
+ content_spiece_model = self.sp_model.serialized_model_proto()
82
+ fi.write(content_spiece_model)
83
+
84
+ if os.path.abspath(self.merge_file) != os.path.abspath(out_merge_file):
85
+ shutil.copyfile(self.merge_file, out_merge_file)
86
+
87
+ return out_vocab_file, out_merge_file
88
+
89
+ def _convert_token_to_id(self, token: str):
90
+ return self.encoder.get(token, self.encoder[self.unk_token])
91
+
92
+ def _convert_id_to_token(self, id: int):
93
+ return self.decoder.get(id, self.unk_token)
94
+
95
+ def prepare_preprocess(self):
96
+ self.uniChars = "àáảãạâầấẩẫậăằắẳẵặèéẻẽẹêềếểễệđìíỉĩịòóỏõọôồốổỗộơờớởỡợùúủũụưừứửữựỳýỷỹỵÀÁẢÃẠÂẦẤẨẪẬĂẰẮẲẴẶÈÉẺẼẸÊỀẾỂỄỆĐÌÍỈĨỊÒÓỎÕỌÔỒỐỔỖỘƠỜỚỞỠỢÙÚỦŨỤƯỪỨỬỮỰỲÝỶỸỴÂĂĐÔƠƯ"
97
+ self.unsignChars = "aaaaaaaaaaaaaaaaaeeeeeeeeeeediiiiiooooooooooooooooouuuuuuuuuuuyyyyyAAAAAAAAAAAAAAAAAEEEEEEEEEEEDIIIOOOOOOOOOOOOOOOOOOOUUUUUUUUUUUYYYYYAADOOU"
98
+
99
+ self.dict_char = {}
100
+ char1252 = 'à|á|ả|ã|ạ|ầ|ấ|ẩ|ẫ|ậ|ằ|ắ|ẳ|ẵ|ặ|è|é|ẻ|ẽ|ẹ|ề|ế|ể|ễ|ệ|ì|í|ỉ|ĩ|ị|ò|ó|ỏ|õ|ọ|ồ|ố|ổ|ỗ|ộ|ờ|ớ|ở|ỡ|ợ|ù|ú|ủ|ũ|ụ|ừ|ứ|ử|ữ|ự|ỳ|ý|ỷ|ỹ|ỵ|À|Á|Ả|Ã|Ạ|Ầ|Ấ|Ẩ|Ẫ|Ậ|Ằ|Ắ|Ẳ|Ẵ|Ặ|È|É|Ẻ|Ẽ|Ẹ|Ề|Ế|Ể|Ễ|Ệ|Ì|Í|Ỉ|Ĩ|Ị|Ò|Ó|Ỏ|Õ|Ọ|Ồ|Ố|Ổ|Ỗ|Ộ|Ờ|Ớ|Ở|Ỡ|Ợ|Ù|Ú|Ủ|Ũ|Ụ|Ừ|Ứ|Ử|Ữ|Ự|Ỳ|Ý|Ỷ|Ỹ|Ỵ'.split(
101
+ '|')
102
+ charutf8 = "à|á|ả|ã|ạ|ầ|ấ|ẩ|ẫ|ậ|ằ|ắ|ẳ|ẵ|ặ|è|é|ẻ|ẽ|ẹ|ề|ế|ể|ễ|ệ|ì|í|ỉ|ĩ|ị|ò|ó|ỏ|õ|ọ|ồ|ố|ổ|ỗ|ộ|ờ|ớ|ở|ỡ|ợ|ù|ú|ủ|ũ|ụ|ừ|ứ|ử|ữ|ự|ỳ|ý|ỷ|ỹ|ỵ|À|Á|Ả|Ã|Ạ|Ầ|Ấ|Ẩ|Ẫ|Ậ|Ằ|Ắ|Ẳ|Ẵ|Ặ|È|É|Ẻ|Ẽ|Ẹ|Ề|Ế|Ể|Ễ|Ệ|Ì|Í|Ỉ|Ĩ|Ị|Ò|Ó|Ỏ|Õ|Ọ|Ồ|Ố|Ổ|Ỗ|Ộ|Ờ|Ớ|Ở|Ỡ|Ợ|Ù|Ú|Ủ|Ũ|Ụ|Ừ|Ứ|Ử|Ữ|Ự|Ỳ|Ý|Ỷ|Ỹ|Ỵ".split(
103
+ '|')
104
+ for i in range(len(char1252)):
105
+ self.dict_char[char1252[i]] = charutf8[i]
106
+
107
+ self.bang_nguyen_am = [['a', 'à', 'á', 'ả', 'ã', 'ạ', 'a'],
108
+ ['ă', '��', 'ắ', 'ẳ', 'ẵ', 'ặ', 'aw'],
109
+ ['â', 'ầ', 'ấ', 'ẩ', 'ẫ', 'ậ', 'aa'],
110
+ ['e', 'è', 'é', 'ẻ', 'ẽ', 'ẹ', 'e'],
111
+ ['ê', 'ề', 'ế', 'ể', 'ễ', 'ệ', 'ee'],
112
+ ['i', 'ì', 'í', 'ỉ', 'ĩ', 'ị', 'i'],
113
+ ['o', 'ò', 'ó', 'ỏ', 'õ', 'ọ', 'o'],
114
+ ['ô', 'ồ', 'ố', 'ổ', 'ỗ', 'ộ', 'oo'],
115
+ ['ơ', 'ờ', 'ớ', 'ở', 'ỡ', 'ợ', 'ow'],
116
+ ['u', 'ù', 'ú', 'ủ', 'ũ', 'ụ', 'u'],
117
+ ['ư', 'ừ', 'ứ', 'ử', 'ữ', 'ự', 'uw'],
118
+ ['y', 'ỳ', 'ý', 'ỷ', 'ỹ', 'ỵ', 'y']]
119
+ self.bang_ky_tu_dau = ['', 'f', 's', 'r', 'x', 'j']
120
+
121
+ self.nguyen_am_to_ids = {}
122
+
123
+ for i in range(len(self.bang_nguyen_am)):
124
+ for j in range(len(self.bang_nguyen_am[i]) - 1):
125
+ self.nguyen_am_to_ids[self.bang_nguyen_am[i][j]] = (i, j)
126
+
127
+ self.sp_word_sub = {
128
+ "@@": "confuseeyes",
129
+ "℅": "%",
130
+ r"/": " fraction ",
131
+ r":\)+": "smileface",
132
+ r";\)+": "smileface",
133
+ r":\*+": "kissingface",
134
+ r"=\)+": "playfulsmileface",
135
+ r"=\(+": "playfulsadface",
136
+ r":\(+": "sadface",
137
+ r":3+": "threeface",
138
+ r":v+": "vface",
139
+ r"\^\^": "kindsmile",
140
+ r"\^_\^": "kindmountsmile",
141
+ r"\^\.\^": "kindmountsmile",
142
+ r"-_-": "disapointface",
143
+ r"\._\.": "confusedface",
144
+ r":>+": "cutesmile",
145
+ r"(\|)w(\|)": "fancycryface",
146
+ r":\|": "mutedface",
147
+ r":d+": "laughface",
148
+ r"<3": "loveicon",
149
+ r"\.{2,}": "threedot",
150
+ r"-{1,}>{1,}": "arrow",
151
+ r"={1,}>{1,}": "arrow",
152
+ r"(\d+)h": r"\1 giờ",
153
+ r"(\d+)'": r"\1 phút",
154
+ r"(\d+)trieu": r"\1 triệu",
155
+ r"(\d+)\s?tr": r"\1 triệu",
156
+ r"blut\w+": "bluetooth",
157
+ r"(\d+)\s\*": r"\1 sao"
158
+ }
159
+
160
+ self.replace_dict = {
161
+ "/": "fraction",
162
+ "wf": "wifi",
163
+ "wifj": "wifi",
164
+ "wjfj": "wifi",
165
+ "wjfi": "wifi",
166
+ "wiffi": "wifi",
167
+ "wj": "wifi",
168
+ "ko": "không",
169
+ "k": "không",
170
+ "hong": "không",
171
+ "đc": "được",
172
+ "sp": "sản phẩm",
173
+ "fb": "facebook",
174
+ "ytb": "youtube",
175
+ "yt": "youtube",
176
+ "mes": "messenger",
177
+ "mess": "messenger",
178
+ "tgdđ": "thegioididong",
179
+ "nv": "nhân viên",
180
+ "ss": "samsung",
181
+ "ip": "iphone",
182
+ "appel": "apple",
183
+ "oke": "ok",
184
+ "okie": "ok",
185
+ "okey": "ok",
186
+ "oki": "ok",
187
+ "oce": "ok",
188
+ "okela": "ok",
189
+ "mk": "mình",
190
+ "sd": "sử dụng",
191
+ "sdung": "sử dụng",
192
+ "ae": "anh em",
193
+ "lq": "liên quân",
194
+ "lqmb": "liên quân mobile",
195
+ "lun": "luôn",
196
+ "ng": "người",
197
+ "ad": "admin",
198
+ "ms": "mới",
199
+ "cx": "cũng",
200
+ "cũg": "cũng",
201
+ "nhìu": "nhiều",
202
+ "bth": "bình thường",
203
+ "bthg": "bình thường",
204
+ "ngta": "người ta",
205
+ "dow": "download",
206
+ "hdh": "hệ điều hành",
207
+ "hđh": "hệ điều hành",
208
+ "cammera": "camera",
209
+ "dt": "điện thoại",
210
+ "dthoai": "điện thoại",
211
+ "dth": "điện thoại",
212
+ "đth": "điện thoại",
213
+ "hk": "không",
214
+ "j": "gì",
215
+ "ji": "gì",
216
+ "mn": "mọi người",
217
+ "m.n": "mọi người",
218
+ "mjh": "mình",
219
+ "mjk": "mình",
220
+ "lắc": "lag",
221
+ "lác": "lag",
222
+ "lang": "lag",
223
+ "nhah": "nhanh",
224
+ "nóichung": "nói chung",
225
+ "zl": "zalo",
226
+ "sóg": "sóng",
227
+ "rẽ": "rẻ",
228
+ "trc": "trước",
229
+ "chíp": "chip",
230
+ "bin": "pin",
231
+ "lm": "làm",
232
+ "bik": "biết",
233
+ "hog": "không",
234
+ "zỏm": "dổm",
235
+ "z": "vậy",
236
+ "v": "vậy",
237
+ "nhah": "nhanh",
238
+ "r": "rồi",
239
+ "ỗn": "ổn",
240
+ "nhìu": "nhiều",
241
+ "wá": "quá",
242
+ "wep": "web",
243
+ "wed": "web",
244
+ "fim": "phim",
245
+ "film": "phim",
246
+ "xạc": "sạc",
247
+ "xài": "sài",
248
+ "het": "hết",
249
+ "lun": "luôn",
250
+ "e": "em",
251
+ "a": "anh",
252
+ "bjo": "bây giờ",
253
+ "vl": "vãi lồn",
254
+ "sac": "sạc",
255
+ "vidieo": "video",
256
+ "tét": "test",
257
+ "tes": "test",
258
+ "thik": "thích",
259
+ "fai": "phải",
260
+ "✋": "tay",
261
+ "🔋": "pin",
262
+ "☆": "sao",
263
+ "supper": "super",
264
+ "lổi": "lỗi",
265
+ "loát": "load",
266
+ "thui": "thôi",
267
+ "rùi": "rồi",
268
+ "ỗn": "ổn",
269
+ "lổi": "lỗi",
270
+ "suống": "xuống",
271
+ "selfi": "selfie",
272
+ "gg": "google",
273
+ "cam on": "cảm ơn",
274
+ "tg": "thời gian",
275
+ "nchung": "nói chung",
276
+ "❤": "loveicon",
277
+ "trại nghiệm": "trải nghiệm",
278
+ "dất": "rất",
279
+ "đứg": "đứng",
280
+ "bằg": "bằng",
281
+ "mìh": "mình",
282
+ "đag": "đang",
283
+ "thoi": "thôi",
284
+ "củng": "cũng",
285
+ "đả": "đã",
286
+ "màng": "màn",
287
+ "ff": "free fire",
288
+ "cod": "call of duty",
289
+ "moi thứ": "mọi thứ",
290
+ "moi thu": "mọi thứ",
291
+ "moi thư": "mọi thứ",
292
+ "moi người": "mọi người",
293
+ "moi": "mới",
294
+ "dk": "được",
295
+ "đk": "được",
296
+ "nhậy": "nhạy",
297
+ "ak": "á",
298
+ "ghe": "nghe",
299
+ "bùn": "buồn",
300
+ "bit": "biết",
301
+ "bít": "biết",
302
+ "bnhieu": "bao nhiêu",
303
+ "dụg": "dụng",
304
+ "tk": "tài khoản",
305
+ "sąc": "sạc",
306
+ "rât": "rât",
307
+ "haz": "haiz",
308
+ "sai làm": "sai lầm",
309
+ "flim": "film",
310
+ "xướt": "xước",
311
+ "viềng": "viền"
312
+ }
313
+
314
+ def convert_unicode(self, text: str):
315
+ return re.sub(
316
+ r'à|á|ả|ã|ạ|ầ|ấ|ẩ|ẫ|ậ|ằ|ắ|ẳ|ẵ|ặ|è|é|ẻ|ẽ|ẹ|ề|ế|ể|ễ|ệ|ì|í|ỉ|ĩ|ị|ò|ó|ỏ|õ|ọ|ồ|ố|ổ|ỗ|ộ|ờ|ớ|ở|ỡ|ợ|ù|ú|ủ|ũ|ụ|ừ|ứ|ử|ữ|ự|ỳ|ý|ỷ|ỹ|ỵ|À|Á|Ả|Ã|Ạ|Ầ|Ấ|Ẩ|Ẫ|Ậ|Ằ|Ắ|Ẳ|Ẵ|Ặ|È|É|Ẻ|Ẽ|Ẹ|Ề|Ế|Ể|Ễ|Ệ|Ì|Í|Ỉ|Ĩ|Ị|Ò|Ó|Ỏ|Õ|Ọ|Ồ|Ố|Ổ|Ỗ|Ộ|Ờ|Ớ|Ở|Ỡ|Ợ|Ù|Ú|Ủ|Ũ|Ụ|Ừ|Ứ|Ử|Ữ|Ự|Ỳ|Ý|Ỷ|Ỹ|Ỵ',
317
+ lambda x: self.dict_char[x.group()], text
318
+ )
319
+
320
+ def is_valid_vietnam_word(self, word):
321
+ chars = list(word)
322
+ nguyen_am_index = -1
323
+ for index, char in enumerate(chars):
324
+ x, y = self.nguyen_am_to_ids.get(char, (-1, -1))
325
+ if x != -1:
326
+ if nguyen_am_index == -1:
327
+ nguyen_am_index = index
328
+ else:
329
+ if index - nguyen_am_index != 1:
330
+ return False
331
+ nguyen_am_index = index
332
+ return True
333
+
334
+ def chuan_hoa_dau_tu_tieng_viet(self, word):
335
+ if not self.is_valid_vietnam_word(word):
336
+ return word
337
+
338
+ chars = list(word)
339
+ dau_cau = 0
340
+ nguyen_am_index = []
341
+ qu_or_gi = False
342
+ for index, char in enumerate(chars):
343
+ x, y = self.nguyen_am_to_ids.get(char, (-1, -1))
344
+ if x == -1:
345
+ continue
346
+ elif x == 9: # check qu
347
+ if index != 0 and chars[index - 1] == 'q':
348
+ chars[index] = 'u'
349
+ qu_or_gi = True
350
+ elif x == 5: # check gi
351
+ if index != 0 and chars[index - 1] == 'g':
352
+ chars[index] = 'i'
353
+ qu_or_gi = True
354
+ if y != 0:
355
+ dau_cau = y
356
+ chars[index] = self.bang_nguyen_am[x][0]
357
+ if not qu_or_gi or index != 1:
358
+ nguyen_am_index.append(index)
359
+ if len(nguyen_am_index) < 2:
360
+ if qu_or_gi:
361
+ if len(chars) == 2:
362
+ x, y = self.nguyen_am_to_ids.get(chars[1])
363
+ chars[1] = self.bang_nguyen_am[x][dau_cau]
364
+ else:
365
+ x, y = self.nguyen_am_to_ids.get(chars[2], (-1, -1))
366
+ if x != -1:
367
+ chars[2] = self.bang_nguyen_am[x][dau_cau]
368
+ else:
369
+ chars[1] = self.bang_nguyen_am[5][dau_cau] if chars[1] == 'i' else self.bang_nguyen_am[9][dau_cau]
370
+ return ''.join(chars)
371
+ return word
372
+
373
+ for index in nguyen_am_index:
374
+ x, y = self.nguyen_am_to_ids[chars[index]]
375
+ if x == 4 or x == 8: # ê, ơ
376
+ chars[index] = self.bang_nguyen_am[x][dau_cau]
377
+ # for index2 in nguyen_am_index:
378
+ # if index2 != index:
379
+ # x, y = nguyen_am_to_ids[chars[index]]
380
+ # chars[index2] = bang_nguyen_am[x][0]
381
+ return ''.join(chars)
382
+
383
+ if len(nguyen_am_index) == 2:
384
+ if nguyen_am_index[-1] == len(chars) - 1:
385
+ x, y = self.nguyen_am_to_ids[chars[nguyen_am_index[0]]]
386
+ chars[nguyen_am_index[0]] = self.bang_nguyen_am[x][dau_cau]
387
+ # x, y = nguyen_am_to_ids[chars[nguyen_am_index[1]]]
388
+ # chars[nguyen_am_index[1]] = bang_nguyen_am[x][0]
389
+ else:
390
+ # x, y = nguyen_am_to_ids[chars[nguyen_am_index[0]]]
391
+ # chars[nguyen_am_index[0]] = bang_nguyen_am[x][0]
392
+ x, y = self.nguyen_am_to_ids[chars[nguyen_am_index[1]]]
393
+ chars[nguyen_am_index[1]] = self.bang_nguyen_am[x][dau_cau]
394
+ else:
395
+ # x, y = nguyen_am_to_ids[chars[nguyen_am_index[0]]]
396
+ # chars[nguyen_am_index[0]] = bang_nguyen_am[x][0]
397
+ x, y = self.nguyen_am_to_ids[chars[nguyen_am_index[1]]]
398
+ chars[nguyen_am_index[1]] = self.bang_nguyen_am[x][dau_cau]
399
+ # x, y = nguyen_am_to_ids[chars[nguyen_am_index[2]]]
400
+ # chars[nguyen_am_index[2]] = bang_nguyen_am[x][0]
401
+ return ''.join(chars)
402
+
403
+ def chuan_hoa_dau_cau_tieng_viet(self, sentence):
404
+ """
405
+ Chuyển câu tiếng việt về chuẩn gõ dấu kiểu cũ.
406
+ :param sentence:
407
+ :return:
408
+ """
409
+ words = sentence.split()
410
+ for index, word in enumerate(words):
411
+ cw = re.sub(r'(^\p{P}*)([p{L}.]*\p{L}+)(\p{P}*$)', r'\1/\2/\3', word).split('/')
412
+ # print(cw)
413
+ if len(cw) == 3:
414
+ cw[1] = self.chuan_hoa_dau_tu_tieng_viet(cw[1])
415
+ words[index] = ''.join(cw)
416
+ return ' '.join(words)
417
+
418
+ def normalize(self, text: str, track_change=False):
419
+ # Lowercase
420
+ text = text.lower()
421
+
422
+ text = re.sub(r"((https?|ftp|file):\/{2,3})+([-\w+&@#/%=~|$?!:,.]*)|(www.)+([-\w+&@#/%=~|$?!:,.]*)", "urllink", text)
423
+
424
+ # Remove dup trailing chars (troiiiii -> troi)
425
+ text = re.sub(r"([\D\w])\1+\b", r"\1", text)
426
+ if track_change:
427
+ print("Dedup trailing: ", text)
428
+
429
+ # Replace special symbol to word
430
+ for pttn, repl in self.sp_word_sub.items():
431
+ text = re.sub(fr"{pttn}", f" {repl} ", text)
432
+ if track_change:
433
+ print("Replace special word: ", text)
434
+
435
+ # Correct misspelled word
436
+ def replace(match):
437
+ orig = match.group(1)
438
+ word = " " + self.replace_dict.get(orig, orig) + " "
439
+ return word
440
+ text = re.sub(r"\b(\S+)\b", replace, text)
441
+ if track_change:
442
+ print("Correct misspelled word: ", text)
443
+
444
+ # Normalize string encoding
445
+ text = self.convert_unicode(text)
446
+ if track_change:
447
+ print("Normalize string encoding: ", text)
448
+
449
+ # Vietnamese unicode normalization
450
+ text = self.chuan_hoa_dau_cau_tieng_viet(text)
451
+ if track_change:
452
+ print("Vietnamese unicode normalization: ", text)
453
+
454
+ # Eliminate decimal delimiter (9.000 -> 9000)
455
+ text = re.sub(r"(?<=\d)\.(?=\d{3})", "", text)
456
+ if track_change:
457
+ print("Eliminate decimal delimiter: ", text)
458
+
459
+ # Split between value and unit (300km -> 300 km)
460
+ text = re.sub(r"(\d+)(\D+)", r"\1 \2", text)
461
+ if track_change:
462
+ print("Split between value and unit: ", text)
463
+
464
+ # Split by punctuations
465
+ text = " ".join(
466
+ re.split("(["+re.escape("!\"#$%&\'()*+,-./:;<=>?@[\\]^`{|}~")+"])", text)
467
+ )
468
+ if track_change:
469
+ print("Split by punctuations: ", text)
470
+
471
+ # Split by emoticons
472
+ text = " ".join(
473
+ re.split("(["
474
+ u"\U0001F600-\U0001F64F" # emoticons
475
+ u"\U0001F300-\U0001F5FF" # symbols & pictographs
476
+ u"\U0001F680-\U0001F6FF" # transport & map symbols
477
+ u"\U0001F1E0-\U0001F1FF" # flags (iOS)
478
+ u"\U00002702-\U000027B0"
479
+ u"\U000024C2-\U0001F251"
480
+ u"\U0001f926-\U0001f937"
481
+ u'\U00010000-\U0010ffff'
482
+ u"\u200d"
483
+ u"\u2640-\u2642"
484
+ u"\u2600-\u2B55"
485
+ u"\u23cf"
486
+ u"\u23e9"
487
+ u"\u231a"
488
+ u"\u3030"
489
+ u"\ufe0f"
490
+ u"\u221a"
491
+ "])", text)
492
+ )
493
+
494
+ # Word segmentation
495
+ # text = " ".join(vncorenlp.word_segment(text))
496
+
497
+ return text