File size: 24,120 Bytes
34423c9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
"""Tokenization classes for ChineseCharTokenizer."""

from typing import Optional, Tuple, Union
from transformers import BertTokenizer
import numpy as np
import os
import re
import shutil

# https://www.ling.upenn.edu/courses/Spring_2003/ling538/UnicodeRanges.html
# https://www.microfocus.com/documentation/idol/IDOL/Servers/IDOLServer/11.2/Guides/html/English/expert/Content/IDOLExpert/Languages/Script_Ranges.htm
# https://www.ssec.wisc.edu/~tomw/java/unicode.html
# https://character-table.netlify.app/
# https://character-table.netlify.app/french/
# https://www.compart.com/en/unicode/U+31CE 重要:看各个unicode的编码语义信息,属于哪个编码段(block/plane)

# 联合国六个官方语言:阿拉伯文、中文、英文、法文、俄文、西班牙文
# [U_LAT] 拉丁语系的文字,包括英语、法语、西班牙语、德语等
# [U_RUS] 俄语等
# [U_ARA] 表示阿拉伯语
# [U_JAP] 日语
# [U_KOR] 韩语
# [U_LAN] 某种语言的文字,藏语, 泰语等等
# [U_CHI] 未知中文

# [U_PHO] 注音文字,音标等
# [U_RAD] 部首,笔画
# [U_PUN] 标点

# [U_GRE] 希腊字母
# [U_SYM] 各种各样的符号
# [U_COM] 组合符号,包括上下标
# [U_NUM] 序号,包括VIII,(1),(一)等,也包含一些数字
# [U_MAT] 数学符号
# [U_EMO] 表情
# ¤ 货币符号

unicode_map = [
    {'token': '[U_LAT]', 'range': (0x0000, 0x007F), 'meaning': 'Basic Latin', },
    {'token': '[U_LAT]', 'range': (0x0080, 0x00FF), 'meaning': 'C1 Controls and Latin-1 Supplement', },  # 拉丁字符,有德语、法语
    {'token': '[U_LAT]', 'range': (0x0100, 0x017F), 'meaning': 'Latin Extended-A', },  # 有法语,例如œ
    {'token': '[U_LAT]', 'range': (0x0180, 0x024F), 'meaning': 'Latin Extended-B', },  # 有法语,例如Ÿ
    {'token': '[U_PHO]', 'range': (0x0250, 0x02AF), 'meaning': 'IPA Extensions', },  # 国际音标,例如ə
    {'token': '[U_PHO]', 'range': (0x02B0, 0x02FF), 'meaning': 'Spacing Modifier Letters', },  # 国际音标,例如ʳ
    {'token': '[U_PHO]', 'range': (0x0300, 0x036F), 'meaning': 'Combining Diacritical Marks', },  # 变音符号
    {'token': '[U_GRE]', 'range': (0x0370, 0x03FF), 'meaning': 'Greek/Coptic', },  # 希腊字符,例如α
    {'token': '[U_RUS]', 'range': (0x0400, 0x04FF), 'meaning': 'Cyrillic', },  # 有俄语
    {'token': '[U_RUS]', 'range': (0x0500, 0x052F), 'meaning': 'Cyrillic Supplement', },
    {'token': '[U_LAN]', 'range': (0x0530, 0x058F), 'meaning': 'Armenian', },  # 亚美尼亚语,属于印欧语系
    {'token': '[U_LAN]', 'range': (0x0590, 0x05FF), 'meaning': 'Hebrew', },  # 希伯来语,犹太族用,有以色列,属于亚非语系
    {'token': '[U_ARA]', 'range': (0x0600, 0x06FF), 'meaning': 'Arabic', },  # 阿拉伯语,联合国用,有沙特,属于亚非语系
    {'token': '[U_LAN]', 'range': (0x0700, 0x074F), 'meaning': 'Syriac', },  # 古叙利亚语
    {'token': '[U_ARA]', 'range': (0x0750, 0x077F), 'meaning': 'Undefined -> Arabic', },
    {'token': '[U_LAN]', 'range': (0x0780, 0x07BF), 'meaning': 'Thaana', },  # 它拿字母, 马尔代夫用,属于印欧语系
    {'token': '[U_ARA]', 'range': (0x07C0, 0x08FF), 'meaning': 'Undefined -> Arabic', },
    {'token': '[U_LAN]', 'range': (0x0900, 0x097F), 'meaning': 'Devanagari', },  # 梵语, 印度宗教用,属于印欧语系
    {'token': '[U_LAN]', 'range': (0x0980, 0x09FF), 'meaning': 'Bengali/Assamese', },  # 孟加拉语
    {'token': '[U_LAN]', 'range': (0x0A00, 0x0A7F), 'meaning': 'Gurmukhi', },  # 古木基文,彭加语,印度用
    {'token': '[U_LAN]', 'range': (0x0A80, 0x0AFF), 'meaning': 'Gujarati', },  # 古吉拉特语,印度用
    {'token': '[U_LAN]', 'range': (0x0B00, 0x0B7F), 'meaning': 'Oriya', },  # 印度用
    {'token': '[U_LAN]', 'range': (0x0B80, 0x0BFF), 'meaning': 'Tamil', },  # 印度用
    {'token': '[U_LAN]', 'range': (0x0C00, 0x0C7F), 'meaning': 'Telugu', },  # 印度用
    {'token': '[U_LAN]', 'range': (0x0C80, 0x0CFF), 'meaning': 'Kannada', },  # 印度用
    {'token': '[U_LAN]', 'range': (0x0D00, 0x0DFF), 'meaning': 'Malayalam', },  # 印度用
    # {'token': '[U_LAN]', 'range': (0x0D80, 0x0DFF), 'meaning': 'Sinhala', },  # 僧伽罗语,斯里兰卡用,近印度
    {'token': '[U_LAN]', 'range': (0x0E00, 0x0E7F), 'meaning': 'Thai', },  # 泰语
    {'token': '[U_LAN]', 'range': (0x0E80, 0x0EFF), 'meaning': 'Lao', },  # 老挝语
    {'token': '[U_LAN]', 'range': (0x0F00, 0x0FFF), 'meaning': 'Tibetan', },  # 藏语 NOTE: 藏语是否需要单独列出?
    {'token': '[U_LAN]', 'range': (0x1000, 0x109F), 'meaning': 'Myanmar', },  # 缅甸语
    {'token': '[U_LAN]', 'range': (0x10A0, 0x10FF), 'meaning': 'Georgian', },  # 格鲁吉亚语,伊朗也用
    {'token': '[U_KOR]', 'range': (0x1100, 0x11FF), 'meaning': 'Hangul Jamo', },  # 谚文,有古韩语
    {'token': '[U_LAN]', 'range': (0x1200, 0x137F), 'meaning': 'Ethiopic', },  # 埃塞俄比亚语,非洲,仅次于阿拉伯语
    {'token': '[U_LAN]', 'range': (0x1380, 0x139F), 'meaning': 'Undefined -> Ethiopic', },
    {'token': '[U_LAN]', 'range': (0x13A0, 0x13FF), 'meaning': 'Cherokee', },  # 切罗基语,北美原住民
    {'token': '[U_LAN]', 'range': (0x1400, 0x167F), 'meaning': 'Unified Canadian Aboriginal Syllabics', },  # 加拿大澳大利亚音标
    {'token': '[U_LAN]', 'range': (0x1680, 0x169F), 'meaning': 'Ogham', },  # 欧甘字母,古爱尔兰用
    {'token': '[U_LAN]', 'range': (0x16A0, 0x16FF), 'meaning': 'Runic', },  # 卢恩字母,古北欧用
    {'token': '[U_LAN]', 'range': (0x1700, 0x171F), 'meaning': 'Tagalog', },  # 他加禄语,菲律宾及东南亚用
    {'token': '[U_LAN]', 'range': (0x1720, 0x173F), 'meaning': 'Hanunoo', },  # 菲律宾用
    {'token': '[U_LAN]', 'range': (0x1740, 0x175F), 'meaning': 'Buhid', },  # 菲律宾用
    {'token': '[U_LAN]', 'range': (0x1760, 0x177F), 'meaning': 'Tagbanwa', },  # 菲律宾用
    {'token': '[U_LAN]', 'range': (0x1780, 0x17FF), 'meaning': 'Khmer', },  # 高棉语,柬埔寨用
    {'token': '[U_LAN]', 'range': (0x1800, 0x18AF), 'meaning': 'Mongolian', },  # 蒙古语
    {'token': '[U_LAN]', 'range': (0x18B0, 0x18FF), 'meaning': 'Undefined -> Unified Canadian Aboriginal Syllabics', },
    {'token': '[U_LAN]', 'range': (0x1900, 0x194F), 'meaning': 'Limbu', },  # 林布语,尼泊尔用
    {'token': '[U_LAN]', 'range': (0x1950, 0x197F), 'meaning': 'Tai Le', },  # 傣语,云南用
    {'token': '[U_LAN]', 'range': (0x1980, 0x19DF), 'meaning': 'Undefined -> New Tai Lue', },  # 新傣语
    {'token': '[U_LAN]', 'range': (0x19E0, 0x19FF), 'meaning': 'Khmer Symbols', },  # 高棉标点,柬埔寨用
    {'token': '[U_LAN]', 'range': (0x1A00, 0x1CFF), 'meaning': 'Undefined -> Ol Chiki', },  # 桑塔利语,印度用
    {'token': '[U_PHO]', 'range': (0x1D00, 0x1D7F), 'meaning': 'Phonetic Extensions', },  # 音标,例如法语的ᵈ
    {'token': '[U_PHO]', 'range': (0x1D80, 0x1DFF), 'meaning': 'Undefined -> Phonetic Extensions Supplement', },
    {'token': '[U_LAT]', 'range': (0x1E00, 0x1EFF), 'meaning': 'Latin Extended Additional', },  # 拉丁带修饰符号,例如ṡ
    {'token': '[U_GRE]', 'range': (0x1F00, 0x1FFF), 'meaning': 'Greek Extended', },  # 希腊字符带修饰,例如Ᾱ
    {'token': '[U_SYM]', 'range': (0x2000, 0x206F), 'meaning': 'General Punctuation', },  # 各种符号,例如千分之‰
    {'token': '[U_COM]', 'range': (0x2070, 0x209F), 'meaning': 'Superscripts and Subscripts', },  # 上下标,例如₂
    {'token': '¤', 'range': (0x20A0, 0x20CF), 'meaning': 'Currency Symbols', },  # 货币符号,例如欧元€
    {'token': '[U_COM]', 'range': (0x20D0, 0x20FF), 'meaning': 'Combining Diacritical Marks for Symbols', },  # 奇怪的可组合符号
    {'token': '[U_SYM]', 'range': (0x2100, 0x214F), 'meaning': 'Letterlike Symbols', },  # 符号,例如普朗克常数ℎ,摄氏度℃
    {'token': '[U_NUM]', 'range': (0x2150, 0x218F), 'meaning': 'Number Forms', },  # 特殊形式数字,例如三分之一⅓,八Ⅷ
    {'token': '[U_SYM]', 'range': (0x2190, 0x21FF), 'meaning': 'Arrows', },  # 箭头,例如→
    {'token': '[U_MAT]', 'range': (0x2200, 0x22FF), 'meaning': 'Mathematical Operators', },  # 数学符号,例如减号−,不属于∉
    {'token': '[U_SYM]', 'range': (0x2300, 0x23FF), 'meaning': 'Miscellaneous Technical', },  # 杂乱的符号,例如放大倍数⌀,右上角⌝
    {'token': '[U_SYM]', 'range': (0x2400, 0x243F), 'meaning': 'Control Pictures', },  # 描述符:表达控制的符号,例如空␀,退出␛
    {'token': '[U_SYM]', 'range': (0x2440, 0x245F), 'meaning': 'Optical Character Recognition', },  # OCR符号,例如⑀,⑂
    {'token': '[U_NUM]', 'range': (0x2460, 0x24FF), 'meaning': 'Enclosed Alphanumerics', },  # 带框序号,例如①,⒆
    {'token': '[U_SYM]', 'range': (0x2500, 0x257F), 'meaning': 'Box Drawing', },  # 画盒子符,例如┋,┓
    {'token': '[U_SYM]', 'range': (0x2580, 0x259F), 'meaning': 'Block Elements', },  # 画块符,例如▉,▀
    {'token': '[U_SYM]', 'range': (0x25A0, 0x25FF), 'meaning': 'Geometric Shapes', },  # 几何形状,例如△
    {'token': '[U_SYM]', 'range': (0x2600, 0x26FF), 'meaning': 'Miscellaneous Symbols', },  # 杂乱的符号,例如多云☁,女♀
    {'token': '[U_SYM]', 'range': (0x2700, 0x27BF), 'meaning': 'Dingbats', },  # 杂乱的符号✈➓
    {'token': '[U_MAT]', 'range': (0x27C0, 0x27EF), 'meaning': 'Miscellaneous Mathematical Symbols-A', },  # 杂乱的数学符号⟂⟘
    {'token': '[U_SYM]', 'range': (0x27F0, 0x27FF), 'meaning': 'Supplemental Arrows-A', },  # 补充箭头⟹
    {'token': '[U_LAN]', 'range': (0x2800, 0x28FF), 'meaning': 'Braille Patterns', },  # 盲文,点字文,⠝⠟
    {'token': '[U_SYM]', 'range': (0x2900, 0x297F), 'meaning': 'Supplemental Arrows-B', },  # ⥬
    {'token': '[U_MAT]', 'range': (0x2980, 0x29FF), 'meaning': 'Miscellaneous Mathematical Symbols-B', },  # ⭬
    {'token': '[U_MAT]', 'range': (0x2A00, 0x2AFF), 'meaning': 'Supplemental Mathematical Operators', },  # ⪆
    {'token': '[U_SYM]', 'range': (0x2B00, 0x2BFF), 'meaning': 'Miscellaneous Symbols and Arrows'},  # ⭬
    {'token': '[U_LAN]', 'range': (0x2C00, 0x2E7F), 'meaning': 'Undefined -> Coptic', },  # 科普特语,埃塞俄比亚语
    {'token': '[U_RAD]', 'range': (0x2E80, 0x2EFF), 'meaning': 'CJK Radicals Supplement', },  # CJK中日韩统一表意文字,部首,例如⺘
    {'token': '[U_RAD]', 'range': (0x2F00, 0x2FDF), 'meaning': 'Kangxi Radicals', },  # 康熙字典部首
    {'token': '[U_SYM]', 'range': (0x2FE0, 0x2FEF), 'meaning': 'Undefined -> Symbol', },
    {'token': '[U_SYM]', 'range': (0x2FF0, 0x2FFF), 'meaning': 'Ideographic Description Characters', },  # 描述符:表意文字结构,例如上下结构,左右结构,半包围结构
    {'token': '[U_PUN]', 'range': (0x3000, 0x303F), 'meaning': 'CJK Symbols and Punctuation', },  # 中文标点 。
    {'token': '[U_JAP]', 'range': (0x3040, 0x309F), 'meaning': 'Hiragana', },  # 日语平假名
    {'token': '[U_JAP]', 'range': (0x30A0, 0x30FF), 'meaning': 'Katakana', },  # 日语片假名
    {'token': '[U_PHO]', 'range': (0x3100, 0x312F), 'meaning': 'Bopomofo', },  # 汉语拼音字,例如 ㄠㄎ
    {'token': '[U_KOR]', 'range': (0x3130, 0x318F), 'meaning': 'Hangul Compatibility Jamo', },  # 韩文
    {'token': '[U_JAP]', 'range': (0x3190, 0x319F), 'meaning': 'Kanbun (Kunten)', },  # 汉文,日本用
    {'token': '[U_PHO]', 'range': (0x31A0, 0x31BF), 'meaning': 'Bopomofo Extended', },  # 汉语拼音字,例如ㆠ
    {'token': '[U_RAD]', 'range': (0x31C0, 0x31EF), 'meaning': 'Undefined -> CJK Strokes', },  # 汉字笔画
    {'token': '[U_JAP]', 'range': (0x31F0, 0x31FF), 'meaning': 'Katakana Phonetic Extensions', },  # 片假名音标
    {'token': '[U_NUM]', 'range': (0x3200, 0x32FF), 'meaning': 'Enclosed CJK Letters and Months', },  # 汉字序号,例如㈠
    {'token': '[U_SYM]', 'range': (0x3300, 0x33FF), 'meaning': 'CJK Compatibility', },  # 单字符表达单位 平方厘米㎠,毫克㎎,23点㍯
    {'token': '[U_CHI]', 'range': (0x3400, 0x4DBF), 'meaning': 'CJK Unified Ideographs Extension A', },  # 中文罕见字
    {'token': '[U_SYM]', 'range': (0x4DC0, 0x4DFF), 'meaning': 'Yijing Hexagram Symbols', },  # 易经六十四卦,䷁	䷖
    {'token': '[U_CHI]', 'range': (0x4E00, 0x9FAF), 'meaning': 'CJK Unified Ideographs', },  # 中文
    {'token': '[U_CHI]', 'range': (0x9FB0, 0x9FFF), 'meaning': 'Undefined -> CJK Unified Ideographs', },  # 中文
    {'token': '[U_LAN]', 'range': (0xA000, 0xA48F), 'meaning': 'Yi Syllables', },  # 彝文字符,凉山彝族用
    {'token': '[U_LAN]', 'range': (0xA490, 0xA4CF), 'meaning': 'Yi Radicals', },  # 彝文部首
    {'token': '[U_LAN]', 'range': (0xA4D0, 0xABFF), 'meaning': 'Undefined -> Cherokee'},  # 彻罗基族, 北美印第安人
    {'token': '[U_KOR]', 'range': (0xAC00, 0xD7AF), 'meaning': 'Hangul Syllables', },  # 韩语音节
    {'token': '[U_KOR]', 'range': (0xD7B0, 0xD7FF), 'meaning': 'Undefined -> Hangul Jamo Extended-B', },
    {'range': (0xD800, 0xDBFF), 'meaning': 'High Surrogate Area', 'token': '[UNK]'},
    {'range': (0xDC00, 0xDFFF), 'meaning': 'Low Surrogate Area', 'token': '[UNK]'},
    {'range': (0xE000, 0xF8FF), 'meaning': 'Private Use Area', 'token': '[UNK]'},  # NOTE 统计字频时,有很多落无法显示的字符落到了这一区域
    {'token': '[U_CHI]', 'range': (0xF900, 0xFAFF), 'meaning': 'CJK Compatibility Ideographs', },  # 中文
    {'token': '[U_LAT]', 'range': (0xFB00, 0xFB4F), 'meaning': 'Alphabetic Presentation Forms', },  # 拉丁、希伯来语字母排版符号
    {'token': '[U_ARA]', 'range': (0xFB50, 0xFDFF), 'meaning': 'Arabic Presentation Forms-A', },  # 阿拉伯语排版符号
    {'token': '[U_SYM]', 'range': (0xFE00, 0xFE0F), 'meaning': 'Variation Selectors', },  # 描述符: 表示选择第几个
    {'token': '[U_PUN]', 'range': (0xFE10, 0xFE1F), 'meaning': 'Undefined -> Vertical Forms', },  # 竖排标点
    {'token': '[U_COM]', 'range': (0xFE20, 0xFE2F), 'meaning': 'Combining Half Marks', },  # 可组合符号 例如$︡a
    {'token': '[U_PUN]', 'range': (0xFE30, 0xFE4F), 'meaning': 'CJK Compatibility Forms', },  # 中文排版符号,例如竖排的符号︻︼
    {'token': '[U_PUN]', 'range': (0xFE50, 0xFE6F), 'meaning': 'Small Form Variants', },  # 小符号,小逗号﹐,小问号﹖
    {'token': '[U_ARA]', 'range': (0xFE70, 0xFEFF), 'meaning': 'Arabic Presentation Forms-B', },  # 阿拉伯语排版符号
    {'token': '[U_LAT]', 'range': (0xFF00, 0xFFEF), 'meaning': 'Halfwidth and Fullwidth Forms', },  # 中文全角字符0c, TODO: 这里视为拉丁文,应该映射回拉丁的半角字符
    {'token': '[U_SYM]', 'range': (0xFFF0, 0xFFFF), 'meaning': 'Specials', },  # 描述符: 可表示替换等操作
    {'token': '[U_LAN]', 'range': (0x10000, 0x1007F), 'meaning': 'Linear B Syllabary', },  # 线形文字,像象形文字
    {'token': '[U_LAN]', 'range': (0x10080, 0x100FF), 'meaning': 'Linear B Ideograms', },
    {'token': '[U_LAN]', 'range': (0x10100, 0x1013F), 'meaning': 'Aegean Numbers', },  # 爱琴海象形数字
    {'token': '[U_LAN]', 'range': (0x10140, 0x102FF), 'meaning': 'Undefined -> Carian', },
    {'token': '[U_LAN]', 'range': (0x10300, 0x1032F), 'meaning': 'Old Italic', },  # 古意大利
    {'token': '[U_LAN]', 'range': (0x10330, 0x1034F), 'meaning': 'Gothic', },  # 哥特语
    {'range': (0x10350, 0x1037F), 'meaning': 'Undefined', 'token': '[UNK]'},
    {'token': '[U_LAN]', 'range': (0x10380, 0x1039F), 'meaning': 'Ugaritic', },  # 古文字在叙利亚发现
    {'token': '[U_LAN]', 'range': (0x103A0, 0x103FF), 'meaning': 'Undefined -> Old Persian', },  # 古波斯语
    {'token': '[U_LAN]', 'range': (0x10400, 0x1044F), 'meaning': 'Deseret', },  # 北美原住民用
    {'token': '[U_PHO]', 'range': (0x10450, 0x1047F), 'meaning': 'Shavian', },  # 萧伯纳的音标
    {'token': '[U_LAN]', 'range': (0x10480, 0x104AF), 'meaning': 'Osmanya', },  # 索马里曾经用
    {'token': '[U_LAN]', 'range': (0x104B0, 0x107FF), 'meaning': 'Undefined -> Osage', },  # 欧塞奇语
    {'token': '[U_LAN]', 'range': (0x10800, 0x1083F), 'meaning': 'Cypriot Syllabary', },  # 塞浦路斯,地中海岛国
    {'token': '[U_LAN]', 'range': (0x10840, 0x1CFFF), 'meaning': 'Undefined -> Cuneiform, Chakma, Kharoshthi...', },  # 许多种语言,包括楔形文字, 和一些符号𓆝 1319d 𓆟 1319f
    {'token': '[U_LAN]', 'range': (0x1D000, 0x1D0FF), 'meaning': 'Byzantine Musical Symbols', },  # 拜占庭人音乐符号
    {'token': '[U_SYM]', 'range': (0x1D100, 0x1D1FF), 'meaning': 'Musical Symbols', },  # 音乐符号
    {'range': (0x1D200, 0x1D2FF), 'meaning': 'Undefined', 'token': '[UNK]'},
    {'token': '[U_SYM]', 'range': (0x1D300, 0x1D35F), 'meaning': 'Tai Xuan Jing Symbols', },  # 太玄经符号
    {'range': (0x1D360, 0x1D3FF), 'meaning': 'Undefined', 'token': '[UNK]'},
    {'token': '[U_MAT]', 'range': (0x1D400, 0x1D7FF), 'meaning': 'Mathematical Alphanumeric Symbols', },  # 数学中用的字母,例如斜体的字母
    {'token': '[U_LAN]', 'range': (0x1D800, 0x1F003), 'meaning': 'Undefined -> Adlam', },  # 阿德拉姆字母,用于西非
    {'token': '[U_EMO]', 'range': (0x1F004, 0x1FAF8), 'meaning': 'Undefined -> Emoji', },  # emoji
    {'token': '[U_SYM]', 'range': (0x1FAF9, 0x1FFFF), 'meaning': 'Undefined -> Symbols for Legacy Computing', },
    {'token': '[U_CHI]', 'range': (0x20000, 0x2A6DF), 'meaning': 'CJK Unified Ideographs Extension B', },  # 中文罕见字
    {'token': '[U_CHI]', 'range': (0x2A6E0, 0x2F7FF), 'meaning': 'Undefined -> CJK Unified Ideographs Extension F...', },  # 中文罕见字
    {'token': '[U_CHI]', 'range': (0x2F800, 0x2FA1F), 'meaning': 'CJK Compatibility Ideographs Supplement', },  # 中文罕见字
    {'range': (0x2FA20, 0x2FAAF), 'meaning': 'Undefined', 'token': '[UNK]'},
    {'range': (0x2FAB0, 0x2FFFF), 'meaning': 'Unused', 'token': '[UNK]'},
    {'token': '[U_CHI]', 'range': (0x30000, 0x3134F), 'meaning': 'Unused -> CJK Unified Ideographs Extension G (unassigned)', },  # 未使用的中文编码区间
    {'range': (0x31350, 0xDFFFF), 'meaning': 'Unused', 'token': '[UNK]'},
    {'token': '[U_SYM]', 'range': (0xE0000, 0xE007F), 'meaning': 'Tags', },  # 描述符: 表示标签
    {'range': (0xE0080, 0xE00FF), 'meaning': 'Unused', 'token': '[UNK]'},
    {'token': '[U_SYM]', 'range': (0xE0100, 0xE01EF), 'meaning': 'Variation Selectors Supplement', },  # 描述符: 表示选择
    {'range': (0xE01F0, 0xEFFFF), 'meaning': 'Unused', 'token': '[UNK]'},
    {'range': (0xF0000, 0xFFFFD), 'meaning': 'Supplementary Private Use Area-A', 'token': '[UNK]'},
    {'range': (0xFFFFE, 0xFFFFF), 'meaning': 'Unused', 'token': '[UNK]'},
    {'range': (0x100000, 0x10FFFD), 'meaning': 'Supplementary Private Use Area-B', 'token': '[UNK]'},
]


def get_unicode_ranges():
    # 检查区间是否连续
    left_bounds = [m['range'][0] for m in unicode_map]
    right_bounds = [m['range'][1] for m in unicode_map]
    for right, left in zip(right_bounds[:-1], left_bounds[1:]):
        assert right+1 == left
    return np.array(right_bounds)


def _is_chinese_char(cp):
    # copied from transformers.models.bert.tokenization_bert.BasicTokenizer._is_chinese_char
    """Checks whether CP is the codepoint of a CJK character."""
    # This defines a "chinese character" as anything in the CJK Unicode block:
    #   https://en.wikipedia.org/wiki/CJK_Unified_Ideographs_(Unicode_block)
    #
    # Note that the CJK Unicode block is NOT all Japanese and Korean characters,
    # despite its name. The modern Korean Hangul alphabet is a different block,
    # as is Japanese Hiragana and Katakana. Those alphabets are used to write
    # space-separated words, so they are not treated specially and handled
    # like the all of the other languages.
    if (
        (cp >= 0x4E00 and cp <= 0x9FFF)
        or (cp >= 0x3400 and cp <= 0x4DBF)  #
        or (cp >= 0x20000 and cp <= 0x2A6DF)  #
        or (cp >= 0x2A700 and cp <= 0x2B73F)  #
        or (cp >= 0x2B740 and cp <= 0x2B81F)  #
        or (cp >= 0x2B820 and cp <= 0x2CEAF)  #
        or (cp >= 0xF900 and cp <= 0xFAFF)
        or (cp >= 0x2F800 and cp <= 0x2FA1F)  #
    ):  #
        return True

    return False


def show_unicode(start=0x1F004, end=0x1FAF8):
    # emoji 文件 https://www.unicode.org/Public/emoji/latest/emoji-sequences.txt
    # https://github.com/hidehalo/emoji/issues/3
    # https://apps.timwhitlock.info/emoji/tables/unicode
    for i in range(start, end):
        print(chr(i), end=' ')
    print()


def load_json(file):
    import json
    with open(file, 'r', encoding='utf-8') as f:
        obj = json.load(f)
    return obj


class ChineseCharTokenizer(BertTokenizer):
    vocab_files_names = {"vocab_file": "vocab.txt", 'mapping_file': "replace.json"}

    def __init__(self, vocab_file, *args, **kwargs):
        super(ChineseCharTokenizer, self).__init__(vocab_file, *args, **kwargs)
        self.unicoder_ranges = get_unicode_ranges()
        self.enclosed_tokens = {token for token in self.vocab if token[0] == '[' and token[-1] == ']' and 'unused' not in token}
        self.enclosed_tokens_by_len = [
            [token for token in self.enclosed_tokens if len(token) == 5],
            [token for token in self.enclosed_tokens if len(token) == 6],
            [token for token in self.enclosed_tokens if len(token) == 7]
        ]
        self.dir = os.path.join(os.path.dirname(vocab_file))
        self.replace_map = load_json(os.path.join(self.dir, 'replace.json'))

    # # [EOS]相当于逗号、换行,不用看作special token
    def convert_token_to_representative(self, token: str) -> str:
        token = self.replace_map.get(token, token)  # 异体字转换,繁简转换,全半角转换,大小写转换等
        if token in self.vocab:
            return token
        else:
            assert len(token) == 1, token
            if re.match(r'\s', token):  # 匹配\u2003, \t等
                return ' '
            v = ord(token)
            if _is_chinese_char(v):
                return '[U_CHI]'
            elif v <= 0x10FFFD:
                i = np.searchsorted(self.unicoder_ranges, v)  # 找到插入位置 ranges[i-1] < v <= ranges[i]
                return unicode_map[i]['token']
            else:
                return '[UNK]'

    # bert的tokenize会加上CLS?
    def _tokenize(self, text):
        # 如果没有人为加的特殊赋好,可以不用这个tokenize,list(text)就是tokenize的结果
        split_tokens = []
        i = 0
        while i < len(text):
            if text[i:i+5] in self.enclosed_tokens_by_len[0]:
                split_tokens.append(text[i:i+5])
                i += 5
            elif text[i:i+6] == '[MASK]':
                split_tokens.append('[MASK]')
                i += 6
            elif text[i:i+7] in self.enclosed_tokens_by_len[2]:
                split_tokens.append(text[i:i+7])
                i += 7
            else:
                split_tokens.append(self.convert_token_to_representative(text[i]))
                i += 1
        return split_tokens

    def _convert_token_to_id(self, token):
        return self.vocab.get(self.convert_token_to_representative(token), self.vocab.get(self.unk_token))  # BUG: convert_token_to_representative 不是 id!

    def convert_tokens_to_string(self, tokens):
        return ''.join(tokens)

    def save_pretrained(self, save_directory: Union[str, os.PathLike], legacy_format: Optional[bool] = None, filename_prefix: Optional[str] = None, push_to_hub: bool = False, **kwargs) -> Tuple[str]:
        ret = super().save_pretrained(save_directory, legacy_format, filename_prefix, push_to_hub, **kwargs)
        shutil.copyfile(os.path.join(self.dir, 'replace.json'), f'{save_directory}/replace.json')
        shutil.copyfile(os.path.join(self.dir, 'cctokenizer.py'), f'{save_directory}/cctokenizer.py')
        return ret