日常更新; close #198

This commit is contained in:
Dvel 2023-04-13 17:04:44 +08:00
parent bfeb35dccb
commit f1c6b9a47e
23 changed files with 27488 additions and 1443 deletions

View File

@ -30,7 +30,7 @@
# 降低一些几乎只在一个固定词汇中使用的读音的权重,不让其参与注音,在 base 中手动注音。
---
name: 8105
version: "2023-04-11"
version: "2023-04-13"
sort: by_weight
...
### 按需启用
@ -46,6 +46,7 @@ sort: by_weight
嬢 niang 1
薙 ti 1
菈 la 1
卻 que 1
# 注释掉的这几行已经加入到下面并调整到合适的权重了
# ling
# 囧 jiong
@ -1600,7 +1601,7 @@ sort: by_weight
墦 fan 13
𫔍 fan 0
𬸪 fan 0
放 fang 1730745
放 fang 7730745
房 fang 980289
防 fang 406226
方 fang 347176

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
#
#
# 只保留三个字及以上的
# 与 base sogou 没有重复
# 与 base 没有重复
#
#
# - 日常用语
@ -17,7 +17,7 @@
# - [同义词词林2020.3.26修订版](https://forum.freemdict.com/t/topic/1211)
---
name: ext
version: "2023-04-11"
version: "2023-04-13"
sort: by_weight
columns:
- text
@ -3653,6 +3653,7 @@ columns:
一般原则 100
一般啦 100
一般在 100
一般多少斤 100
一般官员 100
一般巨人 100
一般常识 100
@ -10185,9 +10186,6 @@ columns:
不习惯似的 100
不了不了 100
不了之局 100
不了了之了 100
不了了之啊 100
不了了当 100
不了啊 100
不了汉 100
不予理会 100
@ -18774,7 +18772,6 @@ columns:
了不起的 100
了不起的盖茨比 100
了个寂寞 100
了了于心 100
了事环 100
了你的 100
了几分 100
@ -26074,6 +26071,7 @@ columns:
以一警百 100
以一驭万 100
以上的 100
以下几处 100
以下几种 100
以下几种可能 100
以下开放 100
@ -29607,6 +29605,7 @@ columns:
你看看人家 100
你看看你看看 100
你看着他 100
你看着办 100
你看行不行 100
你看谁来 100
你看谁来了 100
@ -32279,7 +32278,6 @@ columns:
光之所向 100
光之祝福 100
光乎乎 100
光了了 100
光二极管 100
光亮亮 100
光伏器件 100
@ -32991,6 +32989,7 @@ columns:
全都去死 100
全都去死吧 100
全都向 100
全都对 100
全都想 100
全都搞定 100
全都搞定了 100
@ -38339,6 +38338,7 @@ columns:
养蜂业 100
养蜂人 100
养蜗牛 100
养词库 100
养起来 100
养身之道 100
养身体 100
@ -38844,6 +38844,7 @@ columns:
写在纸上 100
写在脸上 100
写在脸上了 100
写在这里 100
写多少了 100
写好了吗 100
写完一本 100
@ -39565,6 +39566,7 @@ columns:
准备好了吗 100
准备好了没有 100
准备好的 100
准备导入 100
准备干什么 100
准备年货 100
准备很齐 100
@ -41866,7 +41868,6 @@ columns:
刮龙卷风 100
到一百零八岁 100
到上海了 100
到不了了 100
到中间 100
到中间儿 100
到了另一边 100
@ -42972,7 +42973,6 @@ columns:
动一下手脚 100
动一动了 100
动下手脚 100
动不了了 100
动不动就想 100
动不动就要 100
动不动工 100
@ -46277,6 +46277,7 @@ columns:
厨房里 100
厨神下凡 100
厨神争霸 100
去上坟 100
去上班 100
去不去不 100
去不去啊 100
@ -46313,6 +46314,7 @@ columns:
去创造 100
去前缀 100
去医院检查 100
去南站 100
去厕所 100
去厕所了 100
去取之间 100
@ -46326,6 +46328,8 @@ columns:
去吗去吗 100
去吧少年 100
去听听吧 100
去哪个区 100
去哪个学校 100
去哪儿啊 100
去哪儿玩 100
去哪儿玩儿 100
@ -46338,6 +46342,8 @@ columns:
去国外 100
去外面 100
去大理 100
去大街上 100
去娘家 100
去嫖娼 100
去学校 100
去对付 100
@ -46351,10 +46357,14 @@ columns:
去年买了个 100
去年买了个表 100
去年分数线 100
去年差不多 100
去年底啊 100
去年是 100
去年疫情 100
去年的 100
去年还是前年 100
去年这个时候 100
去年这时候 100
去广告插件 100
去彼取此 100
去得太晚 100
@ -46372,6 +46382,7 @@ columns:
去我家睡 100
去打劫 100
去打暑假工 100
去扫墓 100
去扭转天亮 100
去找你的 100
去找到了 100
@ -46383,16 +46394,21 @@ columns:
去挣钱 100
去换取 100
去捣乱 100
去掉一个 100
去掉注音 100
去插眼 100
去放弃 100
去救援 100
去日本 100
去暗投明 100
去月球 100
去杀胜残 100
去杂去劣 100
去染头发 100
去查一下 100
去查查 100
去查查吧 100
去楼顶 100
去歌唱 100
去死去死 100
去死吧你啊 100
@ -46424,6 +46440,7 @@ columns:
去看了吗 100
去看店 100
去看烟花 100
去看直播 100
去看看 100
去看看呗 100
去睡了 100
@ -46451,6 +46468,7 @@ columns:
去谁的家 100
去走亲戚 100
去超越 100
去跨年 100
去辩解 100
去迟一步 100
去送死 100
@ -46470,6 +46488,7 @@ columns:
去问问吧 100
去阻截 100
去阻挠 100
去领证 100
去领钱 100
去食堂 100
去食堂打饭 100
@ -49607,7 +49626,6 @@ columns:
吃不下了 100
吃不下去 100
吃不习惯 100
吃不了了 100
吃不了苦 100
吃不出啊 100
吃不出来 100
@ -49942,6 +49960,7 @@ columns:
各拉丹冬峰 100
各搞各的 100
各方势力 100
各方案 100
各方满意 100
各方瞩目 100
各显所长 100
@ -52219,6 +52238,7 @@ columns:
咱公司 100
咱又不是 100
咱啥时候 100
咱就是 100
咱是不是 100
咱爸咱妈 100
咳了一声 100
@ -53064,6 +53084,7 @@ columns:
啥事情都能用 100
啥劲头 100
啥啥啥 100
啥地步 100
啥家庭 100
啥建议 100
啥当啥立 100
@ -53351,7 +53372,6 @@ columns:
喝不上 100
喝不下 100
喝不下去 100
喝不了了 100
喝不动 100
喝不动了 100
喝不喝茶 100
@ -56664,6 +56684,7 @@ columns:
国家火山公园 100
国家电力监管委员会 100
国家的 100
国家监委 100
国家科学委员会 100
国家积累 100
国家税务局 100
@ -59778,8 +59799,6 @@ columns:
大借款 100
大停电 100
大傻叉 100
大傻屄 100
大傻逼 100
大元大一统志 100
大兄弟呀 100
大兄弟啊 100
@ -60929,7 +60948,6 @@ columns:
天公不做美 100
天其实并不高 100
天冬苯丙二肽酯 100
天冷了了 100
天凉了 100
天凉好个秋 100
天凤对战平台 100
@ -62743,7 +62761,6 @@ columns:
好一片 100
好一阵儿 100
好上好下 100
好不了了 100
好不到哪儿去 100
好不到哪去 100
好不好使 100
@ -64205,6 +64222,7 @@ columns:
字字珠玉 100
字幕文件 100
字形输入法 100
字或词 100
字打错了 100
字根合体字 100
字根通用码 100
@ -66933,7 +66951,6 @@ columns:
小斯韵 100
小旋风 100
小无相功 100
小时了了大未必佳 100
小时代 100
小时代系列 100
小时候儿 100
@ -72137,6 +72154,7 @@ columns:
开房记录 100
开挂了吗 100
开挂吗 100
开摆了 100
开放三胎 100
开放下载 100
开放与躺平 100
@ -73815,7 +73833,6 @@ columns:
待下去 100
待不下去了 100
待不了 100
待不了了 100
待久了 100
待了一会儿 100
待了一天 100
@ -75285,7 +75302,6 @@ columns:
志足意满 100
志骄意满 100
志高气扬 100
忘不了了 100
忘不了餐厅 100
忘不掉啊 100
忘了原来的方向 100
@ -78316,7 +78332,6 @@ columns:
我上班去了 100
我上课去了 100
我上课啦 100
我下了了 100
我下了哦 100
我下午回家 100
我下咯 100
@ -79025,7 +79040,6 @@ columns:
我去上班了 100
我去上课了 100
我去不了 100
我去不了了 100
我去不可 100
我去你别劝 100
我去你加 100
@ -79076,7 +79090,6 @@ columns:
我发过去 100
我发过去了 100
我发过来 100
我受不了了 100
我受不可 100
我只不过是在 100
我只发现 100
@ -80386,7 +80399,9 @@ columns:
我看看你啊 100
我看看吧 100
我看看啊 100
我看着办 100
我看行哦 100
我看行啊 100
我看还是 100
我看金庸 100
我真不是 100
@ -80660,6 +80675,8 @@ columns:
我试一试 100
我试一试啊 100
我试了 100
我试了是可以 100
我试了是可以的 100
我试试吧 100
我试试啊 100
我试过了 100
@ -81790,7 +81807,6 @@ columns:
打下一个江山 100
打不下 100
打不下的 100
打不了了 100
打不了的 100
打不到车 100
打不动 100
@ -85752,7 +85768,6 @@ columns:
接到旨意 100
接到过 100
接到过的 100
接受不了了 100
接受吗 100
接受啊 100
接受器 100
@ -86349,6 +86364,7 @@ columns:
搞得快把 100
搞得快跟 100
搞得过 100
搞忘了 100
搞成这样 100
搞把戏 100
搞歧视 100
@ -87148,7 +87164,6 @@ columns:
攸攸之口 100
改一个 100
改一点 100
改不了了 100
改不过来 100
改个名 100
改个密码 100
@ -88635,6 +88650,7 @@ columns:
新农合 100
新冠后遗症 100
新冠治疗 100
新冠溯源 100
新冠病毒感染 100
新冠症状 100
新冷战 100
@ -89446,6 +89462,7 @@ columns:
无损伤动脉止血钳 100
无损音乐 100
无支祁 100
无改动 100
无敌不克 100
无敌了 100
无敌啦 100
@ -90614,6 +90631,8 @@ columns:
明摆着的 100
明教教主 100
明文上传 100
明文存储 100
明文存储密码 100
明断是非 100
明新工专 100
明日就到 100
@ -98616,6 +98635,7 @@ columns:
正在探路 100
正在收看 100
正在收看的是 100
正在改 100
正在施法 100
正在核实 100
正在死亡 100
@ -102145,6 +102165,7 @@ columns:
没有默契 100
没权力 100
没权没势 100
没权重 100
没来历 100
没来回 100
没来得 100
@ -102162,6 +102183,7 @@ columns:
没水平 100
没没无闻 100
没沾过血 100
没泄漏 100
没洗干净 100
没流量 100
没流量了 100
@ -103414,7 +103436,6 @@ columns:
洲际飞弹 100
活下来的 100
活不下去了 100
活不了了 100
活不活 100
活不活泼 100
活不起 100
@ -108313,6 +108334,7 @@ columns:
猪刚鬣 100
猪圈里 100
猪圈里的猪 100
猪圈里的猪啊 100
猪太郎 100
猪头一个 100
猪头人 100
@ -108859,7 +108881,6 @@ columns:
玩三国杀 100
玩下去 100
玩不下去 100
玩不了了 100
玩不动 100
玩不我就 100
玩不明白 100
@ -108918,6 +108939,7 @@ columns:
玩儿命啊 100
玩儿命追 100
玩儿啊 100
玩儿完了 100
玩儿家 100
玩儿得转 100
玩儿死你 100
@ -108952,7 +108974,9 @@ columns:
玩失踪 100
玩它一会 100
玩它一会儿 100
玩完了 100
玩完了吗 100
玩完了啊 100
玩客币 100
玩家一号 100
玩家网 100
@ -111223,7 +111247,6 @@ columns:
白丝黑丝 100
白中发 100
白举铁 100
白了了 100
白了头 100
白事红事 100
白云之上 100
@ -113922,7 +113945,6 @@ columns:
睡上去 100
睡上来 100
睡下来 100
睡不了了 100
睡不好觉 100
睡不着啊 100
睡个好觉 100
@ -114768,6 +114790,7 @@ columns:
确认我 100
确认我不是 100
确认收货 100
确认收货后 100
确认框 100
确认的 100
确认这一点 100
@ -116480,6 +116503,8 @@ columns:
穿山鼠 100
穿得太多了 100
穿得少了 100
穿得漂亮点 100
穿得漂亮点儿 100
穿得非常 100
穿搭秀 100
穿搭达人 100
@ -116612,9 +116637,11 @@ columns:
窦公训女 100
窦太后 100
窿缘桉 100
立一个规矩 100
立不世之功 100
立不住脚 100
立个碑 100
立个规矩 100
立为太子 100
立为皇太子 100
立了不少功劳 100
@ -116726,6 +116753,7 @@ columns:
竖起脊梁 100
竖起自然 100
竖鸡蛋 100
站个人 100
站了很久 100
站住别跑 100
站内信 100
@ -117218,7 +117246,6 @@ columns:
等下回 100
等下回我 100
等下我把 100
等不了了 100
等不住 100
等不住想要 100
等不到的爱 100
@ -117608,7 +117635,6 @@ columns:
算谁的 100
算进来 100
箜篌指尖唱 100
管不了了是吧 100
管不了你 100
管不了你了 100
管不了你了是吧 100
@ -127868,6 +127894,7 @@ columns:
裒多益寡 100
裒敛无厌 100
裕后街 100
裕泰茶馆 100
裕溪河 100
裕隆牌 100
裘佳宁 100
@ -128205,6 +128232,7 @@ columns:
要了你的命 100
要了小命 100
要争气 100
要交学费 100
要亮得多 100
要人保管 100
要从此路过 100
@ -128240,8 +128268,10 @@ columns:
要压岁钱 100
要去哪 100
要去哪儿 100
要去哪玩 100
要去哪里 100
要去哪里呀 100
要去超市 100
要参加吗 100
要及时 100
要发就发 100
@ -128283,6 +128313,7 @@ columns:
要小写吗 100
要尝试 100
要尝试着 100
要居家 100
要带什么 100
要带着你 100
要带着你远走 100
@ -128290,10 +128321,14 @@ columns:
要帮忙 100
要帮忙不 100
要干了 100
要开了 100
要开学了 100
要开工 100
要开开心心 100
要开心点 100
要开摄像头 100
要开服 100
要开空调 100
要开黑 100
要弄明白 100
要往哪里去 100
@ -128331,6 +128366,7 @@ columns:
要拿姑娘与它比模样 100
要指定 100
要换宿舍 100
要接送 100
要插入 100
要撑住 100
要改改吗 100
@ -128398,6 +128434,7 @@ columns:
要看的书 100
要睡了嘛 100
要矜持 100
要竞选 100
要答应我 100
要紧事 100
要紧事儿 100
@ -128421,6 +128458,8 @@ columns:
要补课 100
要被打 100
要要要 100
要解封 100
要解锁 100
要言不繁 100
要言之 100
要让你 100
@ -128444,6 +128483,7 @@ columns:
要这么做 100
要这样设计 100
要进宫 100
要进攻 100
要连任了 100
要追上 100
要退赛 100
@ -128460,6 +128500,7 @@ columns:
要问你 100
要闹哪儿样 100
要闹哪样 100
要降温 100
要难一些 100
要靠自己 100
要顺台阶而上 100
@ -129644,7 +129685,6 @@ columns:
访法之旅 100
访美之旅 100
访英之旅 100
访问不了了 100
访问凭证 100
访问凭证信息 100
访问异常 100
@ -129843,6 +129883,7 @@ columns:
试试看呐 100
试试这个 100
试起来 100
试过了吗 100
试都不想试 100
试错性 100
试镜室 100
@ -132516,7 +132557,6 @@ columns:
走上人生巅峰 100
走下流程 100
走不下去 100
走不了了 100
走不出去 100
走不走啊 100
走不通 100
@ -133350,7 +133390,6 @@ columns:
跌进来 100
跑一下 100
跑上跑下 100
跑不了了 100
跑不了寺 100
跑不了庙 100
跑不动了 100
@ -136045,6 +136084,7 @@ columns:
这两个词 100
这两件事 100
这两兄弟 100
这两处 100
这两款 100
这两者的区别 100
这两行 100
@ -137923,8 +137963,6 @@ columns:
选举罢免法 100
选举署 100
选举资格 100
选了了放弃 100
选了放弃了 100
选亚索 100
选什么 100
选优淘劣 100
@ -138655,6 +138693,8 @@ columns:
避风台 100
避风处 100
邀天之幸 100
邀请一个人 100
邀请别人 100
邀请回答 100
邀请我 100
邀请我们 100
@ -140287,7 +140327,6 @@ columns:
都逼成什么样了 100
都那么 100
都铎王朝 100
都错了 100
都阳了 100
都阻止不了 100
都难以 100
@ -142497,6 +142536,7 @@ columns:
问安者 100
问就是 100
问张昭 100
问得不好 100
问得奇怪 100
问我妈 100
问我干嘛 100
@ -143239,6 +143279,8 @@ columns:
阿法尔沙漠 100
阿法狗 100
阿法罗密欧 100
阿波尼亚 100
阿波连 100
阿泰包子 100
阿泰斯特 100
阿滋海默症 100
@ -147464,6 +147506,7 @@ columns:
骂一句 100
骂了一顿 100
骂你了 100
骂傻逼 100
骂出来 100
骂别人 100
骂我干嘛 100
@ -148038,6 +148081,7 @@ columns:
高钧贤 100
高铁侠 100
高铁币 100
高铁战士 100
高铁晚点 100
高铁票 100
高长虹 100

View File

@ -9,10 +9,10 @@
# [腾讯词向量百万词库](https://ai.tencent.com/ailab/nlp/zh/download.html),感谢 @Huandeep 整理 https://github.com/iDvel/rime-ice/issues/24
#
# 只保留三个字及以上的词
# 与 base sogou ext 没有重复
# 与 base ext 没有重复
---
name: tencent
version: "2023-04-11"
version: "2023-04-13"
sort: by_weight
columns:
- text
@ -39380,7 +39380,6 @@ columns:
不得举办 100
不得买 100
不得买卖 100
不得了了 100
不得了啊 100
不得了啦 100
不得了的事 100
@ -88758,9 +88757,6 @@ columns:
了不起的挑战 100
了不起的自己 100
了不起的长城 100
了了了 100
了了了了 100
了了分明 100
了元歌 100
了凡先生 100
了凡尘 100
@ -145558,7 +145554,6 @@ columns:
你看电视 100
你看看别人 100
你看看我 100
你看着办 100
你看见 100
你看见了 100
你看见我 100
@ -261752,7 +261747,6 @@ columns:
卡马波夫 100
卡骆驰 100
卡魔拉 100
卡麦隆 100
卢一峰 100
卢世瑜 100
卢东亮 100
@ -334568,7 +334562,6 @@ columns:
国家的需求 100
国家的需要 100
国家的骄傲 100
国家监委 100
国家监察 100
国家监察体制改革 100
国家监测 100
@ -638717,7 +638710,6 @@ columns:
最后三分钟 100
最后三轮 100
最后上场 100
最后不了了之 100
最后不得已 100
最后两位 100
最后两分钟 100
@ -715501,7 +715493,6 @@ columns:
泰勒公式 100
泰勒希罗 100
泰勒斯 100
泰勒斯威夫特 100
泰勒约翰逊 100
泰华城 100
泰华街 100
@ -860582,7 +860573,6 @@ columns:
算错账 100
算长远账 100
管一鹤 100
管不了了 100
管不了那么多了 100
管不住嘴巴 100
管不住手 100

View File

@ -14,7 +14,7 @@
# 转化应当大写的单词
---
name: en
version: "2023-04-11"
version: "2023-04-13"
sort: by_weight
...
# +_+
@ -735,7 +735,7 @@ amuse amuse
amusement amusement
amusing amusing
Amy Amy
an an
# an an
ana ana
anabolic anabolic
anaheim anaheim
@ -20955,7 +20955,7 @@ York York
yorker yorker
Yorkshire Yorkshire
Yosemite Yosemite
you you
# you you
young young
younger younger
youngest youngest

View File

@ -7,7 +7,7 @@
#
---
name: en_ext
version: "2023-04-11"
version: "2023-04-13"
sort: by_weight
...
# 一些杂项
@ -121,64 +121,6 @@ Chandler Chandler
Phoebe Phoebe
# 补充的人名
Griffiths Griffiths
Chapman Chapman
Walsh Walsh
Matthews Matthews
Patel Patel
Willie Willie
ChillSeph ChillSeph
Ernest Ernest
Phillip Phillip
Teresa Teresa
Doris Doris
Evelyn Evelyn
Cheryl Cheryl
Mildred Mildred
Katherine Katherine
Judith Judith
Janice Janice
Theresa Theresa
Kimberly Kimberly
Denise Denise
Irene Irene
Shirley Shirley
Cynthia Cynthia
Brenda Brenda
Kathleen Kathleen
Jacqueline Jacqueline
Wanda Wanda
Debra Debra
Lois Lois
Carolyn Carolyn
Tina Tina
Phyllis Phyllis
Norma Norma
Paula Paula
Frances Frances
Lillian Lillian
Olivia Olivia
Ava Ava
Isabella Isabella
Sherlock Sherlock
Amelia Amelia
Sophia Sophia
Abigail Abigail
Liam Liam
Noah Noah
Jay Jay
Enya Enya
Juno Juno
Trump Trump
Biden Biden
Joseph Joseph
Braun Braun
Bayes Bayes
Saul Saul
Wick Wick
#///
# 带权重的系列
iPhone iPhone 999
iPhone 14 iPhone 4
@ -254,6 +196,61 @@ Windows 11 Windows 11
# 往下开始都是扩展单词
# +_+
Griffiths Griffiths
Chapman Chapman
Walsh Walsh
Matthews Matthews
Patel Patel
Willie Willie
ChillSeph ChillSeph
Ernest Ernest
Phillip Phillip
Teresa Teresa
Doris Doris
Evelyn Evelyn
Cheryl Cheryl
Mildred Mildred
Katherine Katherine
Judith Judith
Janice Janice
Theresa Theresa
Kimberly Kimberly
Denise Denise
Irene Irene
Shirley Shirley
Cynthia Cynthia
Brenda Brenda
Kathleen Kathleen
Jacqueline Jacqueline
Wanda Wanda
Debra Debra
Lois Lois
Carolyn Carolyn
Tina Tina
Phyllis Phyllis
Norma Norma
Paula Paula
Frances Frances
Lillian Lillian
Olivia Olivia
Ava Ava
Isabella Isabella
Sherlock Sherlock
Amelia Amelia
Sophia Sophia
Abigail Abigail
Liam Liam
Noah Noah
Jay Jay
Enya Enya
Juno Juno
Trump Trump
Biden Biden
Joseph Joseph
Braun Braun
Bayes Bayes
Saul Saul
Wick Wick
RPG RPG
Role-Playing Game RPG
Role-Playing Game RolePlayingGame
@ -892,6 +889,7 @@ Windows Phone WindowsPhone
Workflow Workflow
WorkFlowy WorkFlowy
WWDC WWDC
Apple Worldwide Developers Conference WWDC
Xee Xee
Xeon Xeon
Xmind Xmind
@ -2074,3 +2072,5 @@ Universally Unique Identifier UUID
stargazers stargazers
fallback fallback
Fyne Fyne
Claude Claude
overdue overdue

View File

@ -506,6 +506,8 @@ love love 💓 💕 👩‍❤️‍👨
火上之心 火上之心 ❤️‍🔥
心火 心火 ❤️‍🔥
燃烧的心 燃烧的心 ❤️‍🔥
心在燃烧 心在燃烧 ❤️‍🔥
心在着火 心在着火 ❤️‍🔥
修复受伤的心灵 修复受伤的心灵 ❤️‍🩹
治愈的心 治愈的心 ❤️‍🩹
受伤的心 受伤的心 ❤️‍🩹
@ -2525,6 +2527,7 @@ UFO UFO 🛸
点燃 点燃 🔥
着火 着火 🔥
着火了 着火了 🔥
火了 火了 🔥
波浪 波浪 🌊
浪花 浪花 🌊
万圣节 万圣节 🎃
@ -3656,6 +3659,9 @@ Wi-Fi Wi-Fi 🛜
错 错 ❌ ❎
错号 错号 ❌ ❎
错误 错误 ❌ ❎
叉 叉 ❌ ❎
叉叉 叉叉 ❌ ❎
画叉 画叉 ❌ ❎
卷曲环 卷曲环 ➰
双卷曲环 双卷曲环 ➿
歌记号 歌记号 〽️

View File

@ -1,7 +1,7 @@
# Emoji 映射表
# 根据此文件生成 emoji.txt
#
# version: "2023-04-11"
# version: "2023-04-13"
#
# 中文映射由 Dvel 纯手工打造 https://github.com/iDvel/rime-ice
#
@ -181,7 +181,7 @@ S$ 新加坡元 新加坡币
💟 心型装饰
❣️ 心叹号
💔 伤心 心碎 失恋
❤️‍🔥 火上之心 心火 燃烧的心
❤️‍🔥 火上之心 心火 燃烧的心 心在燃烧 心在着火
❤️‍🩹 修复受伤的心灵 治愈的心 受伤 受伤的心 受伤的心灵 心伤
# ❤
🩷 粉心 粉色心 粉色的心 粉红心
@ -1128,7 +1128,7 @@ S$ 新加坡元 新加坡币
# ☃
⛄ 雪人
☄️ 彗星 哈雷 哈雷彗星
🔥 火 火焰 燃烧 点燃 着火 着火了
🔥 火 火焰 燃烧 点燃 着火 着火了 火了
💧 水珠 水滴
🌊 波浪 浪花
### Activities
@ -1640,8 +1640,8 @@ S$ 新加坡元 新加坡币
✅ 对 对号 对钩 勾选 正确
☑️ 按钮 复选 复选框 复选按钮 打钩 打对钩
✔ 对 对号 对钩 勾选 正确
❌ 错 错号 错误
❎ 错 错号 错误
❌ 错 错号 错误 叉 叉叉 画叉
❎ 错 错号 错误 叉 叉叉 画叉
➰ 卷曲环
➿ 双卷曲环
〽️ 歌记号

View File

@ -1,15 +1,5 @@
module script
go 1.19
go 1.20
require (
github.com/commander-cli/cmd v1.5.0
github.com/deckarep/golang-set/v2 v2.1.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.8.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
require github.com/deckarep/golang-set/v2 v2.3.0

View File

@ -1,21 +1,2 @@
github.com/commander-cli/cmd v1.5.0 h1:zuMGIdRxQb63R+0Wa9G/g7xtF1fwEERdn+fIIKj5ujI=
github.com/commander-cli/cmd v1.5.0/go.mod h1:y9HfHjaDNGRjzpOcMbK43A791NmESwKBkvCSDBCxJ94=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI=
github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
github.com/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g=
github.com/deckarep/golang-set/v2 v2.3.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=

View File

@ -11,49 +11,37 @@ import (
func main() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
// 临时用的
// rime.Temp()
// Emoji 检查和更新
rime.CheckEmoji()
rime.UpdateEmojiTXT()
rime.CheckAndGenerateEmoji()
fmt.Println("--------------------------------------------------")
// 更新搜狗流行词
rime.UpdateSogou()
fmt.Println("--------------------------------------------------")
// 为 sogou、ext、tencent 没权重的词条加上权重,有权重的改为下面设置的权重
rime.AddWeight(rime.SogouPath, rime.DefaultWeight)
// 为 ext、tencent 没权重的词条加上权重,有权重的改为下面设置的权重
rime.AddWeight(rime.ExtPath, rime.DefaultWeight)
rime.AddWeight(rime.TencentPath, rime.DefaultWeight)
fmt.Println("--------------------------------------------------")
// 通用检查
// flag: 1 只有汉字2 汉字+注音3 汉字+注音+权重4 汉字+权重。
go rime.Check(rime.HanziPath, 3)
go rime.Check(rime.BasePath, 3)
go rime.Check(rime.SogouPath, 3)
go rime.Check(rime.ExtPath, 4)
go rime.Check(rime.TencentPath, 4)
// 检查
// _type: 1 只有汉字 2 汉字+注音 3 汉字+注音+权重 4 汉字+权重
rime.Check(rime.HanziPath, 3)
rime.Check(rime.BasePath, 3)
rime.Check(rime.ExtPath, 4)
rime.Check(rime.TencentPath, 4)
fmt.Println("--------------------------------------------------")
wait()
areYouOK()
// 排序
// 排序,顺便去重
rime.Sort(rime.HanziPath, 3)
rime.Sort(rime.BasePath, 3)
rime.Sort(rime.SogouPath, 3) // 对 base 中已经有的,去重
rime.Sort(rime.ExtPath, 4) // 对 base、sogou 中已经有的,去重
rime.Sort(rime.TencentPath, 4) // 对 base、sogou、ext 中已经有的,去重
// rime.SortEnDict(rime.EnPath)
rime.Sort(rime.ExtPath, 4)
rime.Sort(rime.TencentPath, 4)
}
func wait() {
fmt.Println("检查完成后输入 OK 以继续。。。")
func areYouOK() {
fmt.Println("Are you OK:")
var isOK string
_, _ = fmt.Scanf("%s", &isOK)
if strings.ToLower(isOK) != "ok" {
os.Exit(123)
}
fmt.Println("--------------------------------------------------")
}

View File

@ -3,28 +3,33 @@ package rime
import (
"bufio"
"fmt"
mapset "github.com/deckarep/golang-set/v2"
"log"
"os"
"path"
"strconv"
"strings"
"sync"
"time"
"unicode"
"unicode/utf8"
mapset "github.com/deckarep/golang-set/v2"
)
var specialWords = mapset.NewSet[string]() // 特殊词汇列表,不进行任何检查
var polyphoneWords = mapset.NewSet[string]() // 需要注音的多音字列表
var wrongWords = mapset.NewSet[string]() // 异形词、错别字列表
var filterWords = mapset.NewSet[string]() // 与异形词列表同时使用,过滤掉,一般是包含异形词但不是异形词的,比如「作爱」是错的,但「叫作爱」是正确的。
var hanPinyinMap = make(map[string][]string) // 汉字拼音映射map用于检查注音是否正确
var filterPinyins = mapset.NewSet[string]() // 与汉字拼音映射map同时使用过滤掉比如「深厉浅揭qi」只在这个词中念qi并不是错误。
var (
specialWords = mapset.NewSet[string]() // 特殊词汇列表,不进行任何检查
// 初始化特殊词汇列表、多音字列表、异形词列表、汉字拼音映射
polyphoneWords = mapset.NewSet[string]() // 需要注音的字词
wrongWords = mapset.NewSet[string]() // 异形词、错别字
wrongWordsFilter = mapset.NewSet[string]() // 过滤一部分,包含错别字但不是错别字,如「作爱」是错的,但「叫作爱」是对的
hanPinyin = make(map[string][]string) // 汉字拼音映射,用于检查注音是否正确
hanPinyinFilter = mapset.NewSet[string]() // 过滤一部分比如「深厉浅揭qi」只在这个词中念qi并不是错误。
)
// 初始化特殊词汇列表、需要注音列表、错别字列表、拼音列表
func init() {
// 特殊词汇列表 specialWords不进行任何检查
// 特殊词汇列表,不进行任何检查
specialWords.Add("狄尔斯–阿尔德反应")
specialWords.Add("特里斯坦–达库尼亚")
specialWords.Add("特里斯坦–达库尼亚群岛")
@ -37,13 +42,13 @@ func init() {
specialWords.Add("赛博朋克:命运之轮")
specialWords.Add("哈勃–勒梅特定律")
// 需要注音的多音字列表 polyphoneWords
file, err := os.Open("rime/多音字.txt")
// 需要注音的列表
file1, err := os.Open(需要注音TXT)
if err != nil {
log.Fatal(err)
log.Fatalln(err)
}
defer file.Close()
sc := bufio.NewScanner(file)
defer file1.Close()
sc := bufio.NewScanner(file1)
for sc.Scan() {
line := sc.Text()
if strings.HasPrefix(line, "#") {
@ -52,38 +57,36 @@ func init() {
polyphoneWords.Add(line)
}
// 异形词的两个列表 wrongWords filterWords
file, err = os.Open("rime/异形词.txt")
// 错别字的两个列表: wrongWords wrongWordsFilter
file2, err := os.Open(错别字TXT)
if err != nil {
log.Fatal(err)
log.Fatalln(err)
}
defer file.Close()
sc = bufio.NewScanner(file)
defer file2.Close()
sc = bufio.NewScanner(file2)
isMark := false
for sc.Scan() {
line := sc.Text()
if strings.Contains(line, "# -_-") {
if strings.HasPrefix(line, "# -_-") {
isMark = true
continue
}
if !isMark {
wrongWords.Add(line)
} else {
filterWords.Add(line)
wrongWordsFilter.Add(line)
}
}
// 汉字拼音映射的 map
// 字表的所有读音: hanPinyinMap
file, err = os.Open(HanziPath)
// 汉字拼音映射 hanPinyin hanPinyinFilter
// 将所有读音读入 hanPinyin
file3, err := os.Open(HanziPath)
if err != nil {
log.Fatal(err)
log.Fatalln(err)
}
defer file.Close()
defer file3.Close()
isMark = false
sc = bufio.NewScanner(file)
sc = bufio.NewScanner(file3)
for sc.Scan() {
line := sc.Text()
if !isMark {
@ -94,19 +97,19 @@ func init() {
}
parts := strings.Split(line, "\t")
text, code := parts[0], parts[1]
hanPinyinMap[text] = append(hanPinyinMap[text], code)
hanPinyin[text] = append(hanPinyin[text], code)
}
// 给 hanPinyinMap 补充不在字表的读音,和过滤列表 filterPinyins
file, err = os.Open("rime/汉字拼音映射.txt")
// 给 hanPinyin 补充不再字表的读音,和过滤列表 hanPinyinFilter
file4, err := os.Open(汉字拼音映射TXT)
if err != nil {
log.Fatal(err)
log.Fatalln(err)
}
defer file.Close()
sc = bufio.NewScanner(file)
defer file4.Close()
sc = bufio.NewScanner(file4)
isMark = false
for sc.Scan() {
line := sc.Text()
if strings.HasPrefix(line, "#") && !strings.Contains(line, "# -_-") || line == "" {
if strings.HasPrefix(line, "#") && !strings.HasPrefix(line, "# -_-") || line == "" {
continue
}
if strings.HasPrefix(line, "# -_-") {
@ -117,22 +120,24 @@ func init() {
parts := strings.Split(line, " ")
key := parts[0]
values := parts[1:]
hanPinyinMap[key] = append(hanPinyinMap[key], values...)
hanPinyin[key] = append(hanPinyin[key], values...)
} else {
filterPinyins.Add(line)
hanPinyinFilter.Add(line)
}
}
}
// Check 对传入的词库文件进行检查
func Check(dictPath string, flag int) {
// dictPath: 词库文件路径
// _type: 词库类型 1 只有汉字 2 汉字+注音 3 汉字+注音+权重 4 汉字+权重
func Check(dictPath string, _type int) {
// 控制台输出
defer printlnTimeCost("检查 "+path.Base(dictPath), time.Now())
// 打开文件
file, err := os.Open(dictPath)
if err != nil {
log.Fatal(err)
log.Fatalln(err)
}
defer file.Close()
@ -140,103 +145,117 @@ func Check(dictPath string, flag int) {
lineNumber := 0
isMark := false
sc := bufio.NewScanner(file)
var wg sync.WaitGroup
for sc.Scan() {
lineNumber++
line := sc.Text()
if !isMark {
if line == mark {
if strings.HasPrefix(line, mark) {
isMark = true
}
continue
}
// 忽略注释base 里有很多被注释了的词汇,暂时没有删除
if strings.HasPrefix(line, "#") {
continue
wg.Add(1)
go checkLine(dictPath, _type, line, lineNumber, &wg)
}
// 注释以"#"开头,但不是以"# "开头(没有空格)(强迫症晚期)
if strings.HasPrefix(line, "#") && !strings.HasPrefix(line, "# ") {
if err := sc.Err(); err != nil {
log.Fatalln(err)
}
wg.Wait()
}
// 检查一行
func checkLine(dictPath string, _type int, line string, lineNumber int, wg *sync.WaitGroup) {
defer wg.Done()
// 忽略注释base 中有很多被注视了词汇,暂时没有删除
if strings.HasPrefix(line, "#") {
// 注释以 '#' 开头,但不是以 '# '开头(强迫症晚期)
if !strings.HasPrefix(line, "# ") {
fmt.Println("has # but not #␣", line)
}
return
}
// 是否有空行
// 有空行
if strings.TrimSpace(line) == "" {
fmt.Println("空行,行号:", lineNumber)
fmt.Println("empty line", line)
}
// 开头结尾是否有空字符
if line != strings.TrimSpace(line) {
fmt.Printf("开头或结尾有空格:%q\n", line)
// 开头结尾有空格
if strings.HasPrefix(line, " ") || strings.HasSuffix(line, " ") {
fmt.Println()
}
// +---------------------------------------------------------------
// | 通用检查分割为词汇text, 编码code, 权重weight
// | 开始检查分割后的内容,分割为: 词汇text 编码code 权重weight
// +---------------------------------------------------------------
parts := strings.Split(line, "\t")
var text, code, weight string
if flag == 1 && len(parts) == 1 { // 一列,【汉字】:外部词库
switch {
case _type == 1 && len(parts) == 1: // 一列,【汉字】
text = parts[0]
} else if flag == 2 && len(parts) == 2 { // 两列,【汉字+注音】:外部词库
case _type == 2 && len(parts) == 2: // 两列,【汉字+注音】
text, code = parts[0], parts[1]
} else if flag == 3 && len(parts) == 3 { // 三列,【汉字+注音+权重】:字表 base av sogou
case _type == 3 && len(parts) == 3: // 散列,【汉字+注音+权重】
text, code, weight = parts[0], parts[1], parts[2]
} else if flag == 4 && len(parts) == 2 { // 两列,【汉字+权重】ext tencent
case _type == 4 && len(parts) == 2: // 两列,【汉字+权重】
text, weight = parts[0], parts[1]
} else {
log.Fatal("分割错误:", line)
default:
log.Fatalln("分割错误:", line)
}
// 检查:weight 应该是纯数字
// weight 应该是纯数字
if weight != "" {
_, err := strconv.Atoi(weight)
if err != nil {
fmt.Println("weight 非数字:", line)
fmt.Println("❌ weight 非数字:", line)
}
}
// text 和 weight 不应该含有空格
if strings.Contains(text, " ") || strings.Contains(weight, " ") {
fmt.Println("❌ text 和 weight 含有空格:", line)
}
// code 前后不应该有空格
if strings.HasPrefix(code, " ") || strings.HasSuffix(code, " ") {
fmt.Println("❌ code 前后有空格:", line)
}
// code 不应该有非小写字母
for _, r := range code {
if string(r) != " " && !unicode.IsLower(r) {
fmt.Println("❌ code 含有非小写字母:", line)
break
}
}
// 过滤特殊词条
if specialWords.Contains(text) {
continue
return
}
// 检查text 和 weight 不应该含有空格
if strings.Contains(text, " ") || strings.Contains(weight, " ") {
fmt.Println("text 和 weight 不应该含有空格:", line)
}
// 检查code 前后不应该含有空格
if strings.HasPrefix(code, " ") || strings.HasSuffix(code, " ") {
fmt.Println("code 前后不应该含有空格:", line)
}
// 检查code 是否含有非字母,或没有小写
for _, r := range code {
if string(r) != " " && !unicode.IsLower(r) {
fmt.Println("编码含有非字母或大写字母:", line)
break
}
}
// 检查text 是否含有非汉字内容
// text 不应该有非汉字内容,除了间隔号 ·
for _, c := range text {
if string(c) != "·" && !unicode.Is(unicode.Han, c) {
fmt.Println("含有非汉字内容:", line, c)
fmt.Println("❌ text 含有非汉字内容:", line)
break
}
}
// 除了字表,其他词库不应该含有单个的汉字
if dictPath != HanziPath && utf8.RuneCountInString(text) == 1 {
fmt.Println("意外的单个汉字:", line)
fmt.Println("❌ 意外的单个汉字:", line)
}
// 除了 base ,其他词库不应该含有两个字的词汇
// 除了 base其他词库不应该含有两个字的词汇
if dictPath != BasePath && utf8.RuneCountInString(text) == 2 {
fmt.Println("意外的两字词:", line)
fmt.Println("❌ 意外的两字词:", line)
}
// 汉字个数应该与拼音个数相等
// 汉字个数应该和拼音个数相等
if code != "" {
codeCount := len(strings.Split(code, " "))
textCount := utf8.RuneCountInString(text)
@ -247,49 +266,45 @@ func Check(dictPath string, flag int) {
textCount -= 2
}
if textCount != codeCount {
fmt.Println("汉字个数和拼音个数不相等:", text, code)
fmt.Println("❌ 汉字个数 != 拼音个数:", line)
}
}
// +---------------------------------------------------------------
// | 比较耗时的检查
// | 其他检查
// +---------------------------------------------------------------
// 检查拼写错误如「赞zan」写成了zna或者存在字表中没有注音的字
go func() {
if dictPath != HanziPath && (flag == 2 || flag == 3) && !filterPinyins.Contains(text) {
// 需要注音但没有注音的字
if dictPath == ExtPath || dictPath == TencentPath {
for _, word := range polyphoneWords.ToSlice() {
if strings.Contains(text, word) {
fmt.Println("❌ 需要注音:", line)
}
}
}
// 检查拼写错误如「赞zan」写成了zna顺便检查是否存在字表中没有注音的字
if dictPath != HanziPath && (_type == 2 || _type == 3) && !hanPinyinFilter.Contains(text) {
// 把汉字和拼音弄成一一对应关系,「拼音:pin yin」→「拼:pin」「音:yin」
textWithoutDian := strings.ReplaceAll(text, "·", "") // 去掉间隔号
pinyins := strings.Split(code, " ")
i := 0
for _, zi := range textWithoutDian {
if !contains(hanPinyinMap[string(zi)], pinyins[i]) {
if !contains(hanPinyin[string(zi)], pinyins[i]) {
fmt.Printf("注音错误 or 字表未包含的汉字及注音: %s - %s.+%s\n", line, string(zi), pinyins[i])
}
i++
}
}
}()
// 多音字注音问题检查
go func() {
if dictPath == ExtPath || dictPath == TencentPath {
for _, word := range polyphoneWords.ToSlice() {
if strings.Contains(text, word) {
fmt.Printf("多音字注音问题:%q\n", line)
}
}
}
}()
// 异形词检查
go func() {
if dictPath != HanziPath && !filterWords.Contains(text) {
for _, wrongWord := range wrongWords.ToSlice() {
// 错别字检查,最耗时的检查
if dictPath != HanziPath && !wrongWordsFilter.Contains(text) {
wrongWords.Each(func(wrongWord string) bool {
if strings.Contains(text, wrongWord) {
fmt.Printf("异形词汇: %s - %s\n", wrongWord, text)
fmt.Printf("❌ 错别字: %s - %s\n", text, wrongWord)
return true
}
}
}
}()
return false
})
}
}

View File

@ -3,39 +3,36 @@ package rime
import (
"bufio"
"fmt"
mapset "github.com/deckarep/golang-set/v2"
"log"
"os"
"regexp"
"strings"
"time"
"unicode/utf8"
mapset "github.com/deckarep/golang-set/v2"
)
var emojiTXT = "/Users/dvel/Library/Rime/opencc/emoji.txt"
var mappingTXT = "/Users/dvel/Library/Rime/others/emoji-map.txt"
// CheckAndGenerateEmoji
// 检查 emoji-map.txt 是否合法,检查中文映射是否存在于 base 词库中
// 生成 Rime 格式的 emoji.txt
func CheckAndGenerateEmoji() {
// 控制台输出
defer printlnTimeCost("检查、更新 Emoji", time.Now())
type OrderedMap struct {
keys []string
m map[string][]string
checkEmoji()
generateEmoji()
}
// CheckEmoji 检查 Emoji
// 检查 emoji-map.txt 格式书写问题
// 检查所有词条是否与 base 词库存在差集
func CheckEmoji() {
// 控制台输出
defer printlnTimeCost("检查 Emoji 差集", time.Now())
// 检查 emoji-map.txt 是否合法,检查中文映射是否存在于 base 词库中
func checkEmoji() {
// 打开文件
file, err := os.Open(EmojiPath)
file, err := os.Open(EmojiMapPath)
if err != nil {
log.Fatal(err)
log.Fatalln(err)
}
defer file.Close()
// 将 Emoji 加入 set为检测差集做准备
// 将 Emoji 加入一个 set为检测差集做准备
emojiSet := mapset.NewSet[string]()
sc := bufio.NewScanner(file)
for sc.Scan() {
@ -48,91 +45,101 @@ func CheckEmoji() {
if strings.Contains(line, "#") {
continue
}
// 检查是否包含 Tab
// 检查是否包含 Tab
if strings.Contains(line, "\t") {
fmt.Println("❌ 此行包含 Tab", line)
fmt.Println("❌ contains Tab", line)
continue
}
// 开头结尾无效的空格
// 检查:开头结尾无效的空格
if strings.HasPrefix(line, " ") || strings.HasSuffix(line, " ") {
fmt.Println("❌ unexpected space:", line)
fmt.Println("❌ unexpected space", line)
continue
}
// 开始分割
parts := strings.Split(line, " ")
if len(parts) < 2 {
fmt.Println("❌ invalid line:", line)
fmt.Println("❌ invalid line", line)
continue
}
// 加入 emojiSet顺便用一个 tempSet 查重
tempSet := mapset.NewSet[string]()
for _, word := range parts[1:] {
emojiSet.Add(word)
if tempSet.Contains(word) {
fmt.Println("❌ 此行有重复映射:", line)
for _, text := range parts[1:] {
emojiSet.Add(text)
if tempSet.Contains(text) {
fmt.Println("❌ duplicate mapping", text)
} else {
tempSet.Add(word)
tempSet.Add(text)
}
}
}
// 检查 emoji 中的词条是否与 base+sogou+ext 词库存在差集
for _, word := range emojiSet.Difference(BaseSet).ToSlice() {
// 去除英文字母
if match, _ := regexp.MatchString(`[A-Za-z]+`, word); match {
if err := sc.Err(); err != nil {
log.Fatalln(err)
}
// 检查: emoji-map.txt 中的映射是否存在于 base 词库中,有差集即不存在
for _, text := range emojiSet.Difference(BaseSet).ToSlice() {
// 不检查英文
if match, _ := regexp.MatchString(`[a-zA-Z]`, text); match {
continue
}
// 去除一个字的
if utf8.RuneCountInString(word) == 1 {
// 不检查 1 个字的
if utf8.RuneCountInString(text) == 1 {
continue
}
fmt.Println("❌ Emoji 差集:", word)
fmt.Println("❌ Emoji 与 base 的差集:", text)
}
}
// UpdateEmojiTXT 从 emoji-map.txt 生成或更新 emoji.txt
func UpdateEmojiTXT() {
// 控制台输出
defer printlnTimeCost("更新 emoji.txt", time.Now())
// 读取 emoji-map.txt
mappingFile, err := os.Open(mappingTXT)
if err != nil {
log.Fatal(err)
}
defer mappingFile.Close()
om := new(OrderedMap)
om.keys = make([]string, 0)
om.m = make(map[string][]string)
sc := bufio.NewScanner(mappingFile)
for sc.Scan() {
line := sc.Text()
if strings.HasPrefix(line, "#") && !strings.Contains(line, "井号") { // #️⃣被判断为以 # 开头了。。。
continue
}
arr := strings.Split(line, " ")
for _, word := range arr[1:] {
if !contains(om.keys, word) {
om.keys = append(om.keys, word)
}
om.m[word] = append(om.m[word], arr[0])
}
}
// 写入 emoji.txt
emojiFile, err := os.OpenFile(emojiTXT, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
// 从 emoji-map.txt 生成或更新 emoji.txt
func generateEmoji() {
// 打开文件
file, err := os.Open(EmojiMapPath)
if err != nil {
log.Fatalln(err)
}
defer emojiFile.Close()
defer file.Close()
for _, key := range om.keys {
line := key + "\t" + key + " " + strings.Join(om.m[key], " ") + "\n"
_, err := emojiFile.WriteString(line)
// 模拟有序字典
OmKeys := make([]string, 0)
OmMap := make(map[string][]string)
// 将映射读取到字典里
sc := bufio.NewScanner(file)
for sc.Scan() {
line := sc.Text()
if strings.HasPrefix(line, "#") && !strings.Contains(line, "井号") { // 井号的 Emoji 被判断为以 # 开头了。。。
continue
}
parts := strings.Split(line, " ")
for _, text := range parts[1:] {
if !contains(OmKeys, text) {
OmKeys = append(OmKeys, text)
}
OmMap[text] = append(OmMap[text], parts[0])
}
}
if err := sc.Err(); err != nil {
log.Fatalln(err)
}
// 写入 emoji.txt
file, err = os.OpenFile(EmojiPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
log.Fatalln(err)
}
defer file.Close()
for _, key := range OmKeys {
line := key + "\t" + key + " " + strings.Join(OmMap[key], " ") + "\n"
_, err := file.WriteString(line)
if err != nil {
log.Fatalln(err)
}
}
if err := emojiFile.Sync(); err != nil {
log.Fatal(err)
if err := file.Sync(); err != nil {
log.Fatalln(err)
}
}

View File

@ -1,139 +0,0 @@
package rime
import (
"bufio"
"log"
"os"
"sort"
"strings"
mapset "github.com/deckarep/golang-set/v2"
)
// SortEnDict 排序 en.dict.yaml 词库
func SortEnDict(dictPath string) {
file, err := os.OpenFile(dictPath, os.O_RDWR, 0644)
if err != nil {
log.Fatal(err)
}
defer file.Close()
// 前缀内容和词库切片,前者原封不动写入,后者排序后写入
prefixContents := make([]string, 0) // 前置内容切片
contents := make([][]string, 0) // 词库切片
// 读取
isMark := false
sc := bufio.NewScanner(file)
for sc.Scan() {
line := sc.Text()
if !isMark {
prefixContents = append(prefixContents, line)
if line == mark {
isMark = true
}
continue
}
parts := strings.Split(line, "\t")
contents = append(contents, []string{parts[0], parts[1]})
}
// 排序
sort.Slice(contents, func(i, j int) bool {
if contents[i][1] != contents[j][1] {
return strings.ToLower(contents[i][1]) < strings.ToLower(contents[j][1])
}
return false
})
// 准备写入
err = file.Truncate(0)
if err != nil {
log.Fatalln(err)
}
_, err = file.Seek(0, 0)
if err != nil {
log.Fatalln(err)
}
// 写入前缀
for _, line := range prefixContents {
_, err := file.WriteString(line + "\n")
if err != nil {
log.Fatal(err)
}
}
// 写入词库
for _, content := range contents {
_, err := file.WriteString(strings.Join(content, "\t") + "\n")
if err != nil {
log.Fatal(err)
}
}
err = file.Sync()
if err != nil {
log.Fatal(err)
}
}
// 将 en 词库加入 set同时包含被注释的词汇并且都转为小写
func readEnToSet(dictPath string) mapset.Set[string] {
set := mapset.NewSet[string]()
file, err := os.Open(dictPath)
if err != nil {
log.Fatal(err)
}
defer file.Close()
sc := bufio.NewScanner(file)
isMark := false
for sc.Scan() {
line := sc.Text()
if !isMark {
if strings.Contains(line, mark) {
isMark = true
}
continue
}
word := strings.Split(line, "\t")[0]
word = strings.ToLower(word)
if strings.HasPrefix(word, "# ") {
word = strings.TrimLeft(word, "# ")
}
set.Add(word)
}
return set
}
// 把每行只有一个单词的 txt 文本转换为 Rime 格式的词库
func enTxtToRimeDict(txtPath string) {
txtFile, err := os.Open(txtPath)
if err != nil {
log.Fatal(err)
}
defer txtFile.Close()
outFile, err := os.OpenFile("rime/1.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
defer outFile.Close()
sc := bufio.NewScanner(txtFile)
for sc.Scan() {
line := sc.Text()
_, err := outFile.WriteString(line + "\t" + line + "\n")
if err != nil {
log.Fatal(err)
}
}
err = outFile.Sync()
if err != nil {
log.Fatal(err)
}
}

View File

@ -1,129 +0,0 @@
package rime
import (
"bufio"
"fmt"
"log"
"os"
"strings"
"unicode/utf8"
)
// 临时用的或一次性的方法集
func Temp() {
defer os.Exit(1)
}
func dictsDifference(dict1, dict2 string) {
file1Set := readToSet(dict1)
file2Set := readToSet(dict2)
set := file1Set.Difference(file2Set)
fmt.Println(set.ToSlice())
fmt.Println(set.Cardinality())
}
func dictsIntersect(dict1, dict2 string) {
file1Set := readToSet(dict1)
file2Set := readToSet(dict2)
set := file1Set.Intersect(file2Set)
fmt.Println(set.ToSlice())
fmt.Println(set.Cardinality())
}
func enDictsIntersect(dict1, dict2 string) {
file1Set := readEnToSet(dict1)
file2Set := readEnToSet(dict2)
set := file1Set.Difference(file2Set)
// fmt.Println(set.ToSlice())
fmt.Println(set.Cardinality())
file, err := os.OpenFile("rime/1.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
defer file.Close()
for _, word := range set.ToSlice() {
_, err := file.WriteString(word + "\t" + word + "\n")
if err != nil {
log.Fatal(err)
}
}
err = file.Sync()
if err != nil {
log.Fatal(err)
}
}
// 处理一个 Rime 词库,去除掉它两个字及以下的词汇
func processNewDict(dictPath string) {
file, _ := os.Open(dictPath)
defer file.Close()
outFile, _ := os.OpenFile("/Users/dvel/Downloads/1.dict.yaml", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
defer outFile.Close()
sc := bufio.NewScanner(file)
isMark := false
for sc.Scan() {
line := sc.Text()
if !isMark {
if line == "..." {
isMark = true
}
continue
}
text := strings.Split(line, "\t")[0]
if utf8.RuneCountInString(text) <= 2 {
continue
}
outFile.WriteString(line + "\n")
}
outFile.Sync()
}
func get字表汉字拼音映射() {
file, err := os.Open(HanziPath)
if err != nil {
log.Fatal(err)
}
defer file.Close()
HanPinYinMap := make(map[string][]string)
keys := make([]string, 0) // ordered map
isMark := false
sc := bufio.NewScanner(file)
for sc.Scan() {
line := sc.Text()
if !isMark {
if strings.Contains(line, mark) {
isMark = true
}
continue
}
parts := strings.Split(line, "\t")
text, code := parts[0], parts[1]
if !contains(keys, text) {
keys = append(keys, text)
}
HanPinYinMap[text] = append(HanPinYinMap[text], code)
}
tempTXT, err := os.OpenFile("rime/temp.txt", os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0644)
if err != nil {
log.Fatal(err)
}
defer tempTXT.Close()
for _, key := range keys {
s := key + " " + strings.Join(HanPinYinMap[key], " ") + "\n"
_, err := tempTXT.WriteString(s)
if err != nil {
log.Fatal(err)
}
}
err = tempTXT.Sync()
if err != nil {
log.Fatal(err)
}
}

View File

@ -2,61 +2,64 @@ package rime
import (
"bufio"
"crypto/sha1"
"encoding/hex"
"fmt"
"io"
mapset "github.com/deckarep/golang-set/v2"
"log"
"os"
"os/user"
"path"
"path/filepath"
"strconv"
"strings"
"time"
mapset "github.com/deckarep/golang-set/v2"
)
// 一个词的组成部分
// 一个词的组成部分
type lemma struct {
text string // 汉字
code string // 编码
weight int // 权重
}
const (
mark = "# +_+" // 词库中的标记符号,表示从开始检查或排序
HanziPath = "/Users/dvel/Library/Rime/cn_dicts/8105.dict.yaml"
BasePath = "/Users/dvel/Library/Rime/cn_dicts/base.dict.yaml"
SogouPath = "/Users/dvel/Library/Rime/cn_dicts/sogou.dict.yaml"
ExtPath = "/Users/dvel/Library/Rime/cn_dicts/ext.dict.yaml"
TencentPath = "/Users/dvel/Library/Rime/cn_dicts/tencent.dict.yaml"
EmojiPath = "/Users/dvel/Library/Rime/others/emoji-map.txt"
EnPath = "/Users/dvel/Library/Rime/en_dicts/en.dict.yaml"
DefaultWeight = 100 // sogou、ext、tencet 词库中默认的权重数值
)
var (
BaseSet mapset.Set[string]
SogouSet mapset.Set[string]
ExtSet mapset.Set[string]
TencentSet mapset.Set[string]
)
mark = "# +_+" // 词库中的标记符号,表示从这行开始进行检查或排序
DefaultWeight = 100 // ext、tencent 词库中默认的权重
RimeDir = getRimeDir() // Rime 配置目录
func init() {
EmojiMapPath = filepath.Join(RimeDir, "others/emoji-map.txt")
EmojiPath = filepath.Join(RimeDir, "opencc/emoji.txt")
HanziPath = filepath.Join(RimeDir, "cn_dicts/8105.dict.yaml")
BasePath = filepath.Join(RimeDir, "cn_dicts/base.dict.yaml")
ExtPath = filepath.Join(RimeDir, "cn_dicts/ext.dict.yaml")
TencentPath = filepath.Join(RimeDir, "cn_dicts/tencent.dict.yaml")
HanziSet = readToSet(HanziPath)
BaseSet = readToSet(BasePath)
SogouSet = readToSet(SogouPath)
ExtSet = readToSet(ExtPath)
TencentSet = readToSet(TencentPath)
需要注音TXT = filepath.Join(RimeDir, "others/script/rime/需要注音.txt")
错别字TXT = filepath.Join(RimeDir, "others/script/rime/错别字.txt")
汉字拼音映射TXT = filepath.Join(RimeDir, "others/script/rime/汉字拼音映射.txt")
)
// 获取 macOS Rime 配置目录
func getRimeDir() string {
u, err := user.Current()
if err != nil {
log.Fatalln(err)
}
return filepath.Join(u.HomeDir, "Library/Rime")
}
// readToSet 读取词库文件为 set
// 将所有词库读入 set供检查或排序使用
func readToSet(dictPath string) mapset.Set[string] {
set := mapset.NewSet[string]()
file, err := os.Open(dictPath)
if err != nil {
log.Fatal(set)
log.Fatalln(err)
}
defer file.Close()
@ -65,7 +68,7 @@ func readToSet(dictPath string) mapset.Set[string] {
for sc.Scan() {
line := sc.Text()
if !isMark {
if strings.Contains(line, mark) {
if strings.HasPrefix(line, mark) {
isMark = true
}
continue
@ -77,17 +80,19 @@ func readToSet(dictPath string) mapset.Set[string] {
return set
}
// printlnTimeCost 打印耗时时间
// 打印耗时时间
func printlnTimeCost(content string, start time.Time) {
fmt.Printf("%s\t%.2fs\n", content, time.Since(start).Seconds())
// fmt.Printf("%s\t%.2fs\n", content, time.Since(start).Seconds())
printfTimeCost(content, start)
fmt.Println()
}
// printfTimeCost 打印耗时时间
// 打印耗时时间
func printfTimeCost(content string, start time.Time) {
fmt.Printf("%s\t%.2fs", content, time.Since(start).Seconds())
}
// contains slice 是否包含 item
// slice 是否包含 item
func contains(arr []string, item string) bool {
for _, x := range arr {
if item == x {
@ -97,90 +102,22 @@ func contains(arr []string, item string) bool {
return false
}
// getSha1 获取文件 sha1
func getSha1(dictPath string) string {
f, err := os.Open(dictPath)
if err != nil {
log.Fatal(err)
}
defer f.Close()
sha1Handle := sha1.New()
if _, err := io.Copy(sha1Handle, f); err != nil {
log.Fatal(err)
}
return hex.EncodeToString(sha1Handle.Sum(nil))
}
// updateVersion 排序后,如果文件有改动,则修改 version 日期
func updateVersion(dictPath string, oldSha1 string) {
// 判断文件是否有改变
newSha1 := getSha1(dictPath)
if newSha1 == oldSha1 {
fmt.Println()
return
}
fmt.Println(" ...sorted")
// 打开文件
file, err := os.OpenFile(dictPath, os.O_RDWR, 0644)
if err != nil {
log.Fatal(err)
}
defer file.Close()
// 修改那一行
arr := make([]string, 0)
sc := bufio.NewScanner(file)
for sc.Scan() {
line := sc.Text()
if strings.HasPrefix(line, "version:") {
s := fmt.Sprintf("version: \"%s\"", time.Now().Format("2006-01-02"))
arr = append(arr, s)
} else {
arr = append(arr, line)
}
}
// 重新写入
err = file.Truncate(0)
if err != nil {
log.Fatal(err)
}
_, err = file.Seek(0, 0)
if err != nil {
log.Fatal(err)
}
for _, line := range arr {
_, err := file.WriteString(line + "\n")
if err != nil {
log.Fatal(err)
}
}
err = file.Sync()
if err != nil {
log.Fatal(err)
}
}
// AddWeight 为 ext、tencent 没权重的词条加上权重,有权重的改为 weight
func AddWeight(dictPath string, weight int) {
// 控制台输出
printlnTimeCost("加权重\t"+path.Base(dictPath), time.Now())
// 读取文件到 lines 数组
// 读取到 lines 数组
file, err := os.ReadFile(dictPath)
if err != nil {
log.Fatal(err)
}
lines := strings.Split(string(file), "\n")
// 逐行遍历,加上 weight
isMark := false
for i, line := range lines {
if !isMark {
if strings.Contains(line, mark) {
if strings.HasPrefix(line, mark) {
isMark = true
}
continue
@ -199,7 +136,7 @@ func AddWeight(dictPath string, weight int) {
}
}
// 重新写入
// 写入
resultString := strings.Join(lines, "\n")
err = os.WriteFile(dictPath, []byte(resultString), 0644)
if err != nil {

View File

@ -1,312 +0,0 @@
package rime
import (
"bufio"
"fmt"
"io"
"log"
"net/http"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"time"
"unicode/utf8"
"github.com/commander-cli/cmd"
mapset "github.com/deckarep/golang-set/v2"
)
var filterMark = "# *_*" // "# *_*" 和 mark 之间是过滤词列表
var filterList = mapset.NewSet[string]() // 过滤词列表,在这个列表里的词汇,不再写入
// UpdateSogou 更新搜狗流行词
func UpdateSogou() {
// 控制台输出
defer updateVersion(SogouPath, getSha1(SogouPath))
defer printfTimeCost("更新搜狗流行词", time.Now())
makeSogouFilterList() // 0. 准备好过滤词列表
downloadSogou() // 1. 下载搜狗流行词加入到文件末尾
checkAndWrite() // 2. 过滤、去重、排序
PrintNewWords() // 3. 打印新增词汇
// 弄完了删除临时用的文件,否则 VSCode 全局搜索词汇时会搜索到,影响体验
err := os.Remove("./scel2txt/scel/sogou.scel")
if err != nil {
log.Fatal(err)
}
err = os.Remove("./scel2txt/out/luna_pinyin.sogou.dict.yaml")
if err != nil {
log.Fatal(err)
}
err = os.Remove("./scel2txt/out/sogou.txt")
if err != nil {
log.Fatal(err)
}
}
// 准备好过滤词列表 filterList
func makeSogouFilterList() {
file, err := os.Open(SogouPath)
if err != nil {
log.Fatal(err)
}
defer file.Close()
sc := bufio.NewScanner(file)
isFilterMark := false
for sc.Scan() {
line := sc.Text()
if line == mark {
break
}
if !isFilterMark {
if strings.Contains(line, filterMark) {
isFilterMark = true
}
continue
}
// 判断一些可能出错的情况
if !strings.HasPrefix(line, "# ") {
log.Fatal("sogou 过滤列表 无效行:", line)
}
text := strings.TrimPrefix(line, "# ")
if strings.ContainsAny(text, " \t") {
log.Fatal("sogou 过滤列表 包含空字符:", line)
}
// 加入过滤词列表
filterList.Add(text)
}
}
// downloadSogou 下载搜狗流行词加入到文件末尾,如果是新词且不在过滤列表,打印出来
func downloadSogou() {
// 下载
url := "https://pinyin.sogou.com/d/dict/download_cell.php?id=4&name=%E7%BD%91%E7%BB%9C%E6%B5%81%E8%A1%8C%E6%96%B0%E8%AF%8D%E3%80%90%E5%AE%98%E6%96%B9%E6%8E%A8%E8%8D%90%E3%80%91&f=detail"
// 创建 scel/ 和 out/ 文件夹
scelDir := "./scel2txt/scel/"
if _, err := os.Stat(scelDir); os.IsNotExist(err) {
err := os.MkdirAll(scelDir, 0755)
if err != nil {
panic(err)
}
}
outDir := "./scel2txt/out/"
if _, err := os.Stat(outDir); os.IsNotExist(err) {
err := os.MkdirAll(outDir, 0755)
if err != nil {
panic(err)
}
}
// Get the data
resp, err := http.Get(url)
if err != nil {
panic(err)
}
defer resp.Body.Close()
// 创建一个文件用于保存
out, err := os.Create(filepath.Join(scelDir, "sogou.scel"))
if err != nil {
panic(err)
}
defer out.Close()
// 然后将响应流和文件流对接起来
_, err = io.Copy(out, resp.Body)
if err != nil {
panic(err)
}
// 用 Python 进行转换
c := cmd.NewCommand("python3 scel2txt.py", cmd.WithWorkingDir("./scel2txt"))
err = c.Execute()
if err != nil {
fmt.Println(c.Stderr())
log.Fatal(err)
}
fmt.Printf(c.Stdout())
// 加入到现有词库的末尾
sogouFile, err := os.OpenFile(SogouPath, os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
panic(err)
}
defer sogouFile.Close()
download, err := os.ReadFile(filepath.Join(outDir, "sogou.txt"))
if err != nil {
panic(err)
}
_, err = sogouFile.Write(download)
if err != nil {
panic(err)
}
err = sogouFile.Sync()
if err != nil {
log.Fatal(err)
}
}
// checkAndWrite 过滤、去重、排序
func checkAndWrite() {
// 打开文件
file, err := os.OpenFile(SogouPath, os.O_RDWR, 0644)
if err != nil {
log.Fatal(err)
}
defer file.Close()
// 前缀内容和词库切片,以 mark 隔开
prefixContents := make([]string, 0) // 前置内容切片
contents := make([]lemma, 0) // 词库切片
isMark := false
set := mapset.NewSet[string]() // 去重用的 set
sc := bufio.NewScanner(file)
for sc.Scan() {
line := sc.Text()
if !isMark {
prefixContents = append(prefixContents, line)
if strings.Contains(line, mark) {
isMark = true
}
continue
}
// 分割
parts := strings.Split(line, "\t")
var text, code, weight string
switch len(parts) {
case 2:
text, code = parts[0], parts[1]
case 3:
text, code, weight = parts[0], parts[1], parts[2]
default:
log.Fatal("分割错误:", line)
}
// 过滤:两个字及以下的
if utf8.RuneCountInString(text) <= 2 {
continue
}
// 过滤:从过滤列表过滤掉
if filterList.Contains(text) {
continue
}
// 过滤:去重
if set.Contains(text) {
continue
}
set.Add(text)
// 过滤base 中已经有的就不要了
if BaseSet.Contains(text) {
continue
}
// nue → nvelue → lve
if strings.Contains(code, "nue") {
code = strings.ReplaceAll(code, "nue", "nve")
}
if strings.Contains(code, "lue") {
code = strings.ReplaceAll(code, "lue", "lve")
}
// 加入数组,没权重的默认给 DefaultWeight
if weight == "" {
contents = append(contents, lemma{text, code, DefaultWeight})
} else {
weightInt, err := strconv.Atoi(weight)
if err != nil {
log.Fatal(err, line)
}
contents = append(contents, lemma{text, code, weightInt})
}
}
// 排序
sort.Slice(contents, func(i, j int) bool {
if contents[i].code != contents[j].code {
return contents[i].code < contents[j].code
}
if contents[i].text != contents[j].text {
return contents[i].text < contents[j].text
}
return false
})
// 准备写入
err = file.Truncate(0)
if err != nil {
log.Fatal(err)
}
_, err = file.Seek(0, 0)
if err != nil {
log.Fatal(err)
}
// 写入前缀
for _, content := range prefixContents {
_, err := file.WriteString(content + "\n")
if err != nil {
log.Fatal(err)
}
}
// 写入词库
for _, content := range contents {
_, err := file.WriteString(content.text + "\t" + content.code + "\t" + strconv.Itoa(content.weight) + "\n")
if err != nil {
log.Fatal(err)
}
}
err = file.Sync()
if err != nil {
log.Fatal(err)
}
}
// PrintNewWords 打印新增词汇
func PrintNewWords() {
// 对比 sogou 的新旧 set找出新词汇
newSet := readToSet(SogouPath)
newWords := newSet.Difference(SogouSet)
if newWords.Cardinality() == 0 {
return
}
fmt.Println("新增词汇:")
// 打印无注音的
// for _, word := range newWords.ToSlice() {
// fmt.Println(word)
// }
// 把注音也打出来,方便直接校对
file, err := os.Open(SogouPath)
if err != nil {
log.Fatal(err)
}
defer file.Close()
isMark := false
sc := bufio.NewScanner(file)
for sc.Scan() {
line := sc.Text()
if !isMark {
if strings.Contains(line, mark) {
isMark = true
}
continue
}
text := strings.Split(line, "\t")[0]
if newWords.Contains(text) {
fmt.Println(line)
}
}
fmt.Println("count: ", newWords.Cardinality())
// 更新全局的 set方便后续的检查
SogouSet = newSet
}

View File

@ -2,7 +2,11 @@ package rime
import (
"bufio"
"crypto/sha1"
"encoding/hex"
"fmt"
mapset "github.com/deckarep/golang-set/v2"
"io"
"log"
"os"
"path"
@ -10,13 +14,9 @@ import (
"strconv"
"strings"
"time"
mapset "github.com/deckarep/golang-set/v2"
)
// Sort 词库排序,顺便去重
// flag: 1 只有汉字2 汉字+注音3 汉字+注音+权重4 汉字+权重。
func Sort(dictPath string, flag int) {
func Sort(dictPath string, _type int) {
// 控制台输出
defer updateVersion(dictPath, getSha1(dictPath))
defer printfTimeCost("排序 "+path.Base(dictPath), time.Now())
@ -24,49 +24,49 @@ func Sort(dictPath string, flag int) {
// 打开文件
file, err := os.OpenFile(dictPath, os.O_RDWR, 0644)
if err != nil {
log.Fatal(err)
log.Fatalln(err)
}
defer file.Close()
// 前缀内容词库切片,前者原封不动写入,后者排序后写入
prefixContents := make([]string, 0) // 前置内容切片
contents := make([]lemma, 0) // 词库切片
aSet := mapset.NewSet[string]() // 去重用的 set
// 前缀内容切片、词库切片,前者原封不动写入,后者排序后写入
prefixContents := make([]string, 0) // 前置内容
contents := make([]lemma, 0) // 词库
aSet := mapset.NewSet[string]() // 去重用的 set
isMark := false
sc := bufio.NewScanner(file)
for sc.Scan() {
line := sc.Text()
// mark 之前的写入 prefixContents
if !isMark {
// mark 之前的写入 prefixContents
prefixContents = append(prefixContents, line)
if line == mark {
if strings.HasPrefix(line, mark) {
isMark = true
}
continue
}
// 分割为 text、code、weight
// 分割为 text code weight
parts := strings.Split(line, "\t")
text, code, weight := parts[0], "", ""
// 检查分割长度
if (flag == 1 || flag == 2 || flag == 3) && len(parts) != flag {
fmt.Println("分割错误123:", line)
if (_type == 1 || _type == 2 || _type == 3) && len(parts) != _type {
log.Println("分割错误123")
}
if flag == 4 && len(parts) != 2 {
fmt.Println("分割错误4:", line)
if _type == 4 && len(parts) != 2 {
fmt.Println("分割错误4")
}
// 将 base 中注释了但没删除的词汇权重调为 0
// 将 base 中注释了但没删除的词汇权重调为 0
if dictPath == BasePath && strings.HasPrefix(line, "# ") {
parts[2] = "0"
}
// mark 之后的,写入到 contents
// 自身重复的直接排除,不重复的写入
switch flag {
// 词库自身有重复内容则直接排除,不重复的写入到 contents
switch _type {
case 1: // 一列 【汉字】
if aSet.Contains(text) {
fmt.Println("重复:", line)
@ -100,12 +100,13 @@ func Sort(dictPath string, flag int) {
aSet.Add(text)
weight, _ := strconv.Atoi(weight)
contents = append(contents, lemma{text: text, weight: weight})
default:
log.Fatal("分割错误:", line)
}
}
if err := sc.Err(); err != nil {
log.Fatalln(err)
}
// 排序:拼音升序、权重降序、最后直接按 Unicode 编码排序
// 排序:拼音升序,权重降序,最后直接按 Unicode 编码排序
sort.Slice(contents, func(i, j int) bool {
if contents[i].code != contents[j].code {
return contents[i].code < contents[j].code
@ -119,7 +120,7 @@ func Sort(dictPath string, flag int) {
return false
})
// 准备写入
// 准备写入,清空文件,移动指针到开头
err = file.Truncate(0)
if err != nil {
log.Fatalln(err)
@ -133,7 +134,7 @@ func Sort(dictPath string, flag int) {
for _, line := range prefixContents {
_, err := file.WriteString(line + "\n")
if err != nil {
log.Fatal(err)
log.Fatalln(err)
}
}
@ -142,21 +143,19 @@ func Sort(dictPath string, flag int) {
for _, line := range contents {
_, err := file.WriteString(line.text + "\t" + line.code + "\t" + strconv.Itoa(line.weight) + "\n")
if err != nil {
log.Fatal(err)
log.Fatalln(err)
}
}
}
// 其他词库需要从一个或多个词库中去重后再写入
if contains([]string{SogouPath, ExtPath, TencentPath}, dictPath) {
var intersect mapset.Set[string] // 交集,有交集的就是重复的,去掉
// ext tencent 词库需要从一个或多个词库中去重后再写入
if dictPath == ExtPath || dictPath == TencentPath {
var intersect mapset.Set[string] // 交集,有交集的就是重复的
switch dictPath {
case SogouPath:
intersect = SogouSet.Intersect(BaseSet)
case ExtPath:
intersect = ExtSet.Intersect(BaseSet.Union(SogouSet))
intersect = ExtSet.Intersect(BaseSet)
case TencentPath:
intersect = TencentSet.Intersect(BaseSet.Union(SogouSet).Union(ExtSet))
intersect = TencentSet.Intersect(BaseSet.Union(ExtSet))
}
for _, line := range contents {
@ -164,22 +163,17 @@ func Sort(dictPath string, flag int) {
fmt.Printf("%s 重复于其他词库:%s\n", strings.Split(path.Base(dictPath), ".")[0], line.text)
continue
}
str := ""
if flag == 3 { // sogou
str = line.text + "\t" + line.code + "\t" + strconv.Itoa(line.weight) + "\n"
} else if flag == 4 { // ext tencent
str = line.text + "\t" + strconv.Itoa(line.weight) + "\n"
}
_, err := file.WriteString(str)
s := line.text + "\t" + strconv.Itoa(line.weight) + "\n"
_, err := file.WriteString(s)
if err != nil {
log.Fatal(err)
log.Fatalln(err)
}
}
}
// 外部词库或临时文件,只排序,不去重
if !contains([]string{HanziPath, BasePath, SogouPath, ExtPath, TencentPath}, dictPath) {
switch flag {
if !contains([]string{HanziPath, BasePath, ExtPath, TencentPath}, dictPath) {
switch _type {
case 1:
for _, line := range contents {
_, err := file.WriteString(line.text + "\n")
@ -211,6 +205,73 @@ func Sort(dictPath string, flag int) {
}
}
if err := file.Sync(); err != nil {
log.Fatalln(err)
}
}
// 获取文件 sha1
func getSha1(dictPath string) string {
f, err := os.Open(dictPath)
if err != nil {
log.Fatal(err)
}
defer f.Close()
sha1Handle := sha1.New()
if _, err := io.Copy(sha1Handle, f); err != nil {
log.Fatal(err)
}
return hex.EncodeToString(sha1Handle.Sum(nil))
}
// 排序后,如果文件有改动,则修改 version 日期,并输出 "...sorted"
func updateVersion(dictPath string, oldSha1 string) {
// 判断文件是否有改变
newSha1 := getSha1(dictPath)
if newSha1 == oldSha1 {
fmt.Println()
return
}
fmt.Println(" ...sorted")
// 打开文件
file, err := os.OpenFile(dictPath, os.O_RDWR, 0644)
if err != nil {
log.Fatal(err)
}
defer file.Close()
// 修改那一行
arr := make([]string, 0)
sc := bufio.NewScanner(file)
for sc.Scan() {
line := sc.Text()
if strings.HasPrefix(line, "version:") {
s := fmt.Sprintf("version: \"%s\"", time.Now().Format("2006-01-02"))
arr = append(arr, s)
} else {
arr = append(arr, line)
}
}
// 重新写入
err = file.Truncate(0)
if err != nil {
log.Fatal(err)
}
_, err = file.Seek(0, 0)
if err != nil {
log.Fatal(err)
}
for _, line := range arr {
_, err := file.WriteString(line + "\n")
if err != nil {
log.Fatal(err)
}
}
err = file.Sync()
if err != nil {
log.Fatal(err)

View File

@ -1,3 +1,4 @@
话碴
塞普路斯
东蒂汶
苏利南

View File

@ -1,6 +1,16 @@
# 含有需要注音的字的列表:
# 例如在 ext tencent 无注音的词库中,检测到词库中有含有「伎俩」的词汇,但是没有注音,
# 列出来,手动注音放到 main 中。
# 需要进行注音的字词
𪨊
扒拉
伽蓝
穆棱
@ -16,11 +26,9 @@
大王
乐陵
乐亭
伎俩
万俟
会计
# 偻
龟兹
拱券
单于
@ -94,7 +102,6 @@
溃脓
澹台
瀑河
# 炅
炮烙
犍为
番禺
@ -126,14 +133,9 @@
怨艾
自艾
艾安
荸荠
莎草
莘莘
落枕
落实
落色
@ -143,7 +145,6 @@
慰藉
蕴藉
蚌埠
匕首见
匕见
解池
@ -156,10 +157,7 @@
说客
句读
冠豸山
趑趄
迫击
铅山
饼铛
@ -210,7 +208,6 @@
没人
还好
联系
𪨊
奇高
奇迹
了了

View File

@ -1,61 +0,0 @@
# scel2txt
搜狗细胞词库转鼠须管Rime词库使用 Python3 实现
## 使用
将从[搜狗官方词库网站](https://pinyin.sogou.com/dict/)下载的 `*.scel` 文件放入 `scel` 文件夹,然后运行
```shell
python3 scel2txt.py
```
## 生成的文件
* 后缀为 .txt 的同名词库文件
* 自动合并所有 *.txt 文件到 `luna_pinyin.sogou.dict.yaml`
## 搜狗细胞词库scel格式文件 格式说明
按照一定格式保存的 Unicode 编码文件,其中每两个字节表示一个字符(中文汉字或者英文字母)。
主要包括两部分:
1. 全局拼音表,在文件中的偏移值是 0x1540+4, 格式为 (py_idx, py_len, py_str)
- py_idx: 两个字节的整数,代表这个拼音的索引
- py_len: 两个字节的整数,拼音的字节长度
- py_str: 当前的拼音,每个字符两个字节,总长 py_len
2. 汉语词组表,在文件中的偏移值是 0x2628 或 0x26c4, 格式为 (word_count, py_idx_count, py_idx_data, (word_len, word_str, ext_len, ext){word_count}),其中 (word_len, word, ext_len, ext){word_count} 一共重复 word_count 次, 表示拼音的相同的词一共有 word_count 个
- word_count: 两个字节的整数,同音词数量
- py_idx_count: 两个字节的整数,拼音的索引个数
- py_idx_data: 两个字节表示一个整数,每个整数代表一个拼音的索引,拼音索引数
- word_len:两个字节的整数,代表中文词组字节数长度
- word_str: 汉语词组,每个中文汉字两个字节,总长度 word_len
- ext_len: 两个字节的整数,可能代表扩展信息的长度,好像都是 10
- ext: 扩展信息,一共 10 个字节,前两个字节是一个整数(不知道是不是词频),后八个字节全是 0ext_len 和 ext 一共 12 个字节
## 目前已测试的词库
* [网络流行新词【官方推荐】](https://pinyin.sogou.com/dict/detail/index/4), 24923 个词
* [最详细的全国地名大全](https://pinyin.sogou.com/dict/detail/index/1316), 114572 个词
* [开发大神专用词库【官方推荐】](https://pinyin.sogou.com/dict/detail/index/75228), 430 个词
* [中国高等院校(大学)大全【官方推荐】](https://pinyin.sogou.com/dict/detail/index/20647), 7192 个词
* [宋词精选【官方推荐】](https://pinyin.sogou.com/dict/detail/index/3), 7297 个词
* [成语俗语【官方推荐】](https://pinyin.sogou.com/dict/detail/index/15097), 46785 个词
* [计算机词汇大全【官方推荐】](https://pinyin.sogou.com/dict/detail/index/15117), 10300 个词
* [论语大全【官方推荐】](https://pinyin.sogou.com/dict/detail/index/22406), 2907 个词
* [歇后语集锦【官方推荐】](https://pinyin.sogou.com/dict/detail/index/22418), 1926 个词
* [数学词汇大全【官方推荐】](https://pinyin.sogou.com/dict/detail/index/15202), 15992 个词
* [物理词汇大全【官方推荐】](https://pinyin.sogou.com/dict/detail/index/15203), 13107 个词
* [中国历史词汇大全【官方推荐】](https://pinyin.sogou.com/dict/detail/index/15130), 20526 个词
* [饮食大全【官方推荐】](https://pinyin.sogou.com/dict/detail/index/15201), 6918 个词
* [上海市城市信息精选](https://pinyin.sogou.com/dict/detail/index/19430), 37757 个词
* [linux少量术语](https://pinyin.sogou.com/dict/detail/index/225), 136 个词
## 参考资料
1. [scel2mmseg](https://raw.githubusercontent.com/archerhu/scel2mmseg/master/scel2mmseg.py)
2. [scel-to-txt](https://raw.githubusercontent.com/xwzhong/small-program/master/scel-to-txt/scel2txt.py)

View File

@ -1,168 +0,0 @@
"""
搜狗细胞词库转鼠须管Rime词库
搜狗的 scel 词库是按照一定格式保存的 Unicode 编码文件其中每两个字节表示一个字符中文汉字或者英文字母主要两部分:
1. 全局拼音表在文件中的偏移值是 0x1540+4, 格式为 (py_idx, py_len, py_str)
- py_idx: 两个字节的整数代表这个拼音的索引
- py_len: 两个字节的整数拼音的字节长度
- py_str: 当前的拼音每个字符两个字节总长 py_len
2. 汉语词组表在文件中的偏移值是 0x2628 0x26c4, 格式为 (word_count, py_idx_count, py_idx_data, (word_len, word_str, ext_len, ext){word_count})其中 (word_len, word, ext_len, ext){word_count} 一共重复 word_count , 表示拼音的相同的词一共有 word_count
- word_count: 两个字节的整数同音词数量
- py_idx_count: 两个字节的整数拼音的索引个数
- py_idx_data: 两个字节表示一个整数每个整数代表一个拼音的索引拼音索引数
- word_len:两个字节的整数代表中文词组字节数长度
- word_str: 汉语词组每个中文汉字两个字节总长度 word_len
- ext_len: 两个字节的整数可能代表扩展信息的长度好像都是 10
- ext: 扩展信息一共 10 个字节前两个字节是一个整数(不知道是不是词频)后八个字节全是 0ext_len ext 一共 12 个字节
参考资料
1. https://raw.githubusercontent.com/archerhu/scel2mmseg/master/scel2mmseg.py
2. https://raw.githubusercontent.com/xwzhong/small-program/master/scel-to-txt/scel2txt.py
"""
import struct
import os
import sys
def read_utf16_str(f, offset=-1, len=2):
if offset >= 0:
f.seek(offset)
string = f.read(len)
return string.decode('UTF-16LE')
def read_uint16(f):
return struct.unpack('<H', f.read(2))[0]
def get_hz_offset(f):
mask = f.read(128)[4]
if mask == 0x44:
return 0x2628
elif mask == 0x45:
return 0x26c4
else:
print("不支持的文件类型(无法获取汉语词组的偏移量)")
sys.exit(1)
def get_dict_meta(f):
title = read_utf16_str(f, 0x130, 0x338 - 0x130)
category = read_utf16_str(f, 0x338, 0x540 - 0x338)
desc = read_utf16_str(f, 0x540, 0xd40 - 0x540)
samples = read_utf16_str(f, 0xd40, 0x1540 - 0xd40)
return title, category, desc, samples
def get_py_map(f):
py_map = {}
f.seek(0x1540+4)
while True:
py_idx = read_uint16(f)
py_len = read_uint16(f)
py_str = read_utf16_str(f, -1, py_len)
if py_idx not in py_map:
py_map[py_idx] = py_str
# 如果拼音为 zuo说明是最后一个了
if py_str == 'zuo':
break
return py_map
def get_records(f, file_size, hz_offset, py_map):
f.seek(hz_offset)
records = []
while f.tell() != file_size:
word_count = read_uint16(f)
py_idx_count = int(read_uint16(f) / 2)
py_set = []
for i in range(py_idx_count):
py_idx = read_uint16(f)
if (py_map.get(py_idx, None) == None):
return records
py_set.append(py_map[py_idx])
py_str = " ".join(py_set)
for i in range(word_count):
word_len = read_uint16(f)
word_str = read_utf16_str(f, -1, word_len)
# 跳过 ext_len 和 ext 共 12 个字节
f.read(12)
records.append((py_str, word_str))
return records
def get_words_from_sogou_cell_dict(fname):
with open(fname, 'rb') as f:
hz_offset = get_hz_offset(f)
(title, category, desc, samples) = get_dict_meta(f)
#print("title: %s\ncategory: %s\ndesc: %s\nsamples: %s" %
# (title, category, desc, samples))
py_map = get_py_map(f)
file_size = os.path.getsize(fname)
words = get_records(f, file_size, hz_offset, py_map)
return words
def save(records, f):
records_translated = list(map(lambda x: "%s\t%s" % (
x[1], x[0]), records))
f.write("\n".join(records_translated))
return records_translated
def main():
# 将要转换的词库添加在 scel 目录下
scel_files = list(filter(lambda x: x.endswith('.scel'), [
i for i in os.listdir("./scel")]))
dict_file = "luna_pinyin.sogou.dict.yaml"
dict_file_content = []
dict_file_header = """# Rime dictionary
# encoding: utf-8
#
# Sogou Pinyin Dict - 搜狗细胞词库
#
# https://pinyin.sogou.com/dict/
#
# 包括:
#
%s
#
---
name: luna_pinyin.sogou
version: "1.0"
sort: by_weight
use_preset_vocabulary: true
...
"""
sougo_dict_name_list = list(
map(lambda x: "# * %s" % x.replace(".scel", ""), scel_files))
dict_file_content.append(dict_file_header % "\n".join(sougo_dict_name_list))
for scel_file in scel_files:
records = get_words_from_sogou_cell_dict(
os.path.join("./scel", scel_file))
print("下载搜狗流行词 %s: %s 个词" % (scel_file, len(records)))
with open(os.path.join("./out", scel_file.replace(".scel", ".txt")), "w") as fout:
dict_file_content.extend(save(records, fout))
# print("-"*80)
# print("合并后 %s: %s 个词" % (dict_file, len(dict_file_content) - 1))
with open(os.path.join("./out", dict_file), "w") as dictfout:
dictfout.write("\n".join(dict_file_content))
if __name__ == "__main__":
main()

View File

@ -13,5 +13,5 @@ import_tables:
- cn_dicts/others # 一些杂项
# 建议把扩展词库放到下面,有重复词条时,最上面的权重生效
# - cn_dicts/my_dict
# - cn_dicts/mydict
...