在 rime中州韵小狼毫 自定义词典 一文中,我们分享了如何在rime
中州韵小狼毫须鼠管输入法中定义用户自定义词典;通过自定义词典,我们可以很方便的在输入法中加入个性化的词组。
根据 rime中州韵小狼毫 滤镜与字典的区别 一文所分析,通过自定义词典所定义和管理的个性化词组,会受到输入方案的耦合影响,这导致我们无法方便的直接的分享我们的自定义词典配置;并且对于一些动态词组(例如实时时间,实时日期,电脑信息等),也无法通过配置自定义词典来实现。
本文分享rime
中州韵小狼毫须鼠管输入法的一个联想词组滤镜配置。该滤镜可以在候选列表中出现关键词组时,抛出附加的新的词组,例如下图中带有标记的词组,即为联想词组:
联想词组字典的目的是提供有联想关系的词组,例如由词组“夫妻”,联想到词组“伉俪”,再如由词组“进步”,联想到词组“进步开始于起步”。
联想词组字典是txt
的文档,lua
滤镜脚本支持多个txt
文档分类管理不同的联想词组,且滤镜脚本会自动进行去重处理。
联想词组字典文档内支持以符号#
开头的行作为注释行,以提升词组管理的便捷性。
联想词组文档内的文本分为2
列,以tab
制表符分隔。第1
列为关键词组,关键词组可以有多个,以空格分隔。第2
列为联想词组,联想词组可以有多个,以空格分隔。联想词组的联想是意向的,即只能由第1
更的关键词组联想到第2
列的联想词组,但是可以通过使第1
列与第2
列相等来实现相互联想,例如 “夫妻 伉俪 →夫妻 伉俪”,这样可以使“夫妻”和“伉俪”相互联想。
phraseExt commonPhrase.txt
phraseExt commonPhrase.txt
文档用于管理一般性的公共性的联想词组,phraseExt commonPhrase.txt
词组定义截取如下:
# 支持使用   来定义空格,而正常的空格被用于分词
# 常用链接
知乎 https://www.zhihu.com
百度 度娘 www.baidu.com
淘宝 www.taobao.com
谷歌 谷哥 谷姐 www.google.com
画图 几何 画板 https://webgeo-8gn07v0t78c4ca57-1308819187.tcloudbaseapp.com
# 常用称呼
运气 华盖 运气 华盖
南冠 囚犯 南冠 囚犯
伉俪 夫妻 伉俪 夫妻
丝竹 音乐 丝竹 音乐
烽烟 战争 狼烟 战争 烽烟 狼烟
phraseExt esAppEmoji.txt
phraseExt esAppEmoji.txt
文档用于管理一些应用专属的emoji
表情,例如我们可以在微信聊天中输入 [微笑],则微信会将其自动转换成 emoji
表情符号 。我们在phraseExt esAppEmoji.txt
文档中定义了一系列的此类emoji
表情词组。phraseExt esAppEmoji.txt
词组定义截取如下:
done 完成 搞定 esFs[完成] esDt[Done]
get 了解 知道 esFs[了解] esDt[Get]
no 不行 esFs[No] esFs[叉号] esDt[打叉]
错 错误 esFs[叉号] esDt[打叉]
ok 行 好的 好吧 可以 esFsWxDt[OK]
好 好的 esFs[Yes] esWx[好的]
行 esFs[我看行] esFs[好的]
okr 绩效 esFsDt[OKR]
如上,phraseExt esAppEmoji.txt
文档中的联想词组,以AppName
作为前缀,不同的App
应用,前缀符号映射如下:
应用 | 前缀 |
---|---|
微信 | Wx |
飞书 | Fs |
钉钉 | Dt |
注意:
特别的,AppEmoji
的联想,需要配置应用开关才可以使用,关于应用开关的配置,请参考 rime中州韵小狼毫 weasel.custom.yaml 配置 之 输入环境识别 一文。
phraseExt esUnicode.txt
在Unicode
字符集中,存在着丰富的 emoji
符号,如果不善于利用,则实在可惜。phraseExt esUnicode.txt
文档专门用来管理与 Unicode
表情符号有关的联想词组,phraseExt esUnicode.txt
联想词组定义截取如下:
垃圾 垃圾桶
开水
轮椅 残疾 无障碍 ♿
厕所
厕所 男人 男厕
厕所 女人 女厕
善于使用 Unicode
表情符号,会使你成为一个高情商的人。
phraseExt personal.txt
顾名思义,phraseExt personal.txt
文档是用来管理一些个人和,私有的联想词组的,例如你的电话号码,例如你的邮寄地址,再如你的爱情口头禅。phraseExt personal.txt
联想词组定义示例如下:
# 支持使用   来定义空格,而正常的空间被用于分词
# 这个字典用于管理 个人/私人 信息,以便在共享/分享rime配置时,可以方便的将个人信息进行隔离
# 常用联系方式
电话 手机 123456789AB 123456789AC
快递 地址 湖南省长春市快乐区开心社区2栋305室
# 常用办公信息
工号 000000
邮箱 [email protected]
快递 地址 浙江省杭州市阿里马马集团2号快递收发室
# 其它常用信息
博客 https://www.myblogs.com
如果你与它人分享你的rime
输入法的配置方案,phraseExt personal.txt
的存在将使得你可以快速的将个人/私人信息与配置方案进行隔离。
phraseExt_Module.lua
phraseExt_Module.lua
是一个lua
脚本文档,phraseExt_Module.lua
脚本文档的使用是将以上所管理的联想词组加载到lua
程序中,并提供合适的检索方法接口,以便rime
引擎可以使用联想词功能。phraseExt_Module.lua
脚本内容如下:
-- myPhrase.lua
-- Copyright (C) 2023 yaoyuan.dou
local M={}
local dict={}
local dictPhraseList={}
local dbgFlg = false
--引入系统变更处理模块
local ok, sysInfoRes = pcall(require, 'sysInfo')
local currentDir = sysInfoRes.currentDir
--设置 dbg 开关
local function setDbg(flg)
dbgFlg = flg
sysInfoRes.setDbg(flg)
print('myPhrase dbgFlg is '..tostring(dbgFlg))
end
--将这附串拆散成 table
local function stringSplit(str,sp,sp1)
sp=(type(sp)=="string") and sp or " "
if 0==#sp then
sp="([%z\1-\127\194-\244][\128-\191]*)"
elseif 1==#sp then
sp="[^"..(sp=="%" and "%%" or sp).."]*"
else
sp1=sp1 or "^"
str=str:gsub(sp,sp1)
sp="[^"..sp1.."]*"
end
local tab={}
for v in str:gmatch(sp) do
if ''~=v then
table.insert(tab,v)
end
end
return tab
end
--将文档处理成行数组
local function files_to_lines(...)
if dbgFlg then
print("--->files_to_lines called here")
end
local tab=setmetatable({},{__index=table})
local index=1
for i,filename in next,{...} do
local fn = io.open(filename)
if fn then
for line in fn:lines() do
if not line or #line > 0 then
tab:insert(line)
end
end
fn:close()
end
end
if dbgFlg then
print("--->files_to_lines completed here")
end
return tab
end
local function dictload(...) -- filename)
if dbgFlg then
print("-->dictload called here")
end
local lines=files_to_lines(...)
local thisDict={}
for i,line in next ,lines do
if not line:match("^%s*#") then -- 第一字 # 为注释行
local keys,val = string.match(line,"(.+)\t(%C+)")
if nil ~= keys then
--尝试对关键字进行空格分割
local keyList = stringSplit(keys,' ')
local key=''
for idx=1,#keyList do
key = keyList[idx]
if nil ~= thisDict[key] then
--如果该key已经存在,追加在后面,注意加一个空格
thisDict[key] = thisDict[key]..' '..val
else
thisDict[key] = val
end
end
end
end
end
if dbgFlg then
print("-->dictload completed here")
end
return thisDict
end
--===========================test========================
local function test(printPrefix)
if nil == printPrefix then
printPrefix = ' '
end
if dbgFlg then
print('myPhrase test starting...')
end
sysInfoRes.test(printPrefix..' ')
for k,v in pairs(dict) do
if dbgFlg then
print(printPrefix..k..'\t'..v)
end
end
end
--获取字典中的phraseList
local function getPhraseList(k)
if nil == k then
return {}
elseif '' == k then
return {}
end
--尝试获取 dictPhraseList 中 k 的列表
local phraseList = dictPhraseList[k]
if nil == phraseList then
--phraseList 获取失败,尝试获取 dict 中 k 的字符串
local thisPhrase = dict[k]
if nil == thisPhrase then
--这个 k 在dict中不存在
phraseList={}
elseif thisPhrase == '' then
--这个 k 在dict中是空的
phraseList={}
else
--将获取的 thisPhrase 序列化到 dictPhraseList 中
dictPhraseList[k]=stringSplit(thisPhrase,' ')
--再次从 dictPhraseList 中获取 k 的序列
phraseList = dictPhraseList[k]
end
end
return phraseList
end
function M.init(...)
local files={...}
--文件名不支持中文,其中 # 开始的行为注释行
table.insert(files,"phraseExt commonPhrase.txt")
table.insert(files,"phraseExt esAppEmoji.txt")
table.insert(files,"phraseExt esUnicode.txt")
table.insert(files,"phraseExt personal.txt")
for i,v in next, files do
files[i] = currentDir().."/".. v
end
dict= dictload(table.unpack(files))
--抛出功能函数
M.getPhraseList = getPhraseList
M.setDbg = setDbg
M.test = test
end
M.init()
return M
以上脚本中,我们在M.init()
方法中看到了联想词组字典的加载方法:table.insert(files,"phraseExt personal.txt")
,你如果有其它的联想词组字典,你也可以很方便的加载它们。
phraseExt_Module.lua
脚本提供了一个名为getPhraseList
方法,该方法可以根据指定的关键词组,从联想词组字典对象dict
中检索并返回对应的联想词组。
phraseExt_Filter.lua
phraseExt_Filter.lua
脚本实现了匹配rime
引擎的Filter
滤镜,phraseExt_Filter.lua
脚本定义并返回了phraseExt_Filter
滤镜方法,phraseExt_Filter.lua
脚本内容如下:
-- myPhrase_Filter.lua
-- Copyright (C) 2023 yaoyuan.dou
local dbgFlg = false
local ok, res = pcall(require, 'phraseExt_Module')
local getPhraseList = res.getPhraseList
--最长的comment长度限制
local maxLenOfComment = 250
--设置 dbg 开关
local function setDbg(dbgFlg)
res.setDbg(dbgFlg)
end
--过滤器
local function phraseExt_Filter(input, env)
--获取选项增强开关状态
local on = env.engine.context:get_option("phraseExt")
--获取应用程序标记状态[由于飞书暂不支持文本转表情的输入,帮使用 and false 将其关闭]
local feishuFlg = env.engine.context:get_option("feishuFlg") and false
local wechatFlg = env.engine.context:get_option("wechatFlg")
local qqFlg = env.engine.context:get_option("qqFlg")
local dingdingFlg = env.engine.context:get_option("dingdingFlg")
local minttyFlg = env.engine.context:get_option("minttyFlg")
local cmdFlg = env.engine.context:get_option("cmdFlg")
local pycharmFlg = env.engine.context:get_option("pycharmFlg")
local vscodeFlg = env.engine.context:get_option("vscodeFlg")
local matchedTxt = ''
local esType = ''
local esTxt = ''
local cands={}
local thisTxt
for cand in input:iter() do
--提交默认选项
if nil == cands[cand.text] then
yield(cand)
cands[cand.text]=true
end
if on then
local candTxt = cand.text:gsub("%s","") or ""
if candTxt ~= "" then
--获取增强选项
local phraseList = getPhraseList(candTxt)
if #phraseList > 0 then
local idx
for idx=1,#phraseList do
thisTxt=phraseList[idx]
if nil == cands[thisTxt] then
cands[thisTxt]=true
esType,esTxt = string.match(thisTxt,"^es(.+)(%[.+%])$")
if nil ~= esType then
esType = string.lower(esType)
--这是一个表情选项
if feishuFlg and nil ~= string.find(esType,'fs') then
--这是一个 feishu 表情,且当前在 feishu 中输入
if nil ~= esTxt then
yield(Candidate("word", cand.start, cand._end, esTxt, ''))
end
elseif wechatFlg and nil ~= string.find(esType,'wx') then
--这是一个 wechat 表情,且当前在 wechat 中输入
if nil ~= esTxt then
yield(Candidate("word", cand.start, cand._end, esTxt, ''))
end
elseif qqFlg and nil ~= string.find(esType,'qq') then
--这是一个 QQ 表情,且当前在 QQ 中输入
if nil ~= esTxt then
yield(Candidate("word", cand.start, cand._end, esTxt, ''))
end
elseif dingdingFlg and nil ~= string.find(esType,'dt') then
--这是一个 dingtalk 表情,且当前在 钉钉 中输入
if nil ~= esTxt then
yield(Candidate("word", cand.start, cand._end, esTxt, ''))
end
end
else
--这不是一个表情选项
if string.lower(string.sub(thisTxt, 1, 4)) == 'git-' then
-- 这是一个以 git 开头的选项,这被认为是一个 git 命令
if minttyFlg or cmdFlg then
-- 修剪选项
thisTxt = string.sub(thisTxt, 5)
-- git 命令选项只在 cmd 窗口或者是 mitty 窗口才允许输出,以避免造成干扰
yield(Candidate("word", cand.start, cand._end, thisTxt:gsub(" "," "), ''))
end
elseif string.lower(string.sub(thisTxt, 1, 3)) == 'py-' then
-- 这是一个以 py- 开头的选项,这被认为是一个 python 关键字
if pycharmFlg or vscodeFlg then
-- 修剪选项
thisTxt = string.sub(thisTxt, 4)
-- python 关键字选项只在 pycharm 或者 vscode 中才允许输出, 以避免造成干扰
yield(Candidate("word", cand.start, cand._end, thisTxt:gsub(" "," "), ''))
end
else
yield(Candidate("word", cand.start, cand._end, thisTxt:gsub(" "," "), ''))
end
end
end
end
end
end
end
end
end
return phraseExt_Filter
以下脚本代码中,我们可以看到一组开关状态获取代码,如下:
这些开关变量,使得一些特定的词组(例如App表情)只会在对应的应用程序环境下才会出现。例如只有在微信中进行录入时,才会出现微信专有的emoji
词组,而在txt
环境下录入时,则不会出现微信专属的emoji
词组,这大大提升了输入法的录入体验。
注意:
以上所述文档 phraseExt commonPhrase.txt
、phraseExt esAppEmoji.txt
、phraseExt esUnicode.txt
、phraseExt personal.txt
、phraseExt_Filter.lua
、phraseExt_Module.lua
共6
个文档,应该位于 用户文件夹下的 lua 文件夹内,如下:
rime.lua
rime.lua
脚本的内容如下:
help_translator = require("help")
inputShow_translator = require("inputShow")
inputShow_Filter = require("inputShow_Filter")
Upper_Filter = require("Upper_Filter")
dic_4w_Filter = require("dic_4w_Filter")
phraseReplace_Filter = require("phraseReplace_Filter")
pinyinAdding_Filter = require("pinyinAdding_Filter")
dateTime_Filter = require("dateTime_filter")
dynamicPhrase_Filter = require("dynamicPhrase_Filter")
phraseExt_Filter = require("phraseExt_Filter")
述脚本,在最后一行中,我们加载了phraseExt_Filter
滤镜。
wubi_pinyin.custom.yaml
以上, 我们完成了 phraseExt_Filter
滤镜的所有的功能定义,我们现在需要做的就是在我们的输入方案中配置使用该 phraseExt_Filter
滤镜。此处以五笔・拼音输入方案为例,展示如何配置使用 phraseExt_Filter
滤镜。
在 五笔・拼音 输入方案的方案文档 wubi_pinyin.schema.yaml
的补丁文档 wubi_pinyin.custom.yaml
中,我们增加如下的Filters
配置:
# encoding:utf-8
patch:
switches/+: #增加以下开关
- name: phraseExt # 候选词扩展开关
reset: 1
states: [Off, phraseExt]
engine/filters: # 设置以下filter
- simplifier
- lua_filter@phraseExt_Filter # 自定义短语滤镜,针对响应的关键字,添加新的选项进来
注意,以上配置并不是wubi_pinyin.custom.yaml
的全部配置,此处仅展示了与phraseExt_Filter
有关的部分。
以上所述配置文档,你可以在 rime中州韵小狼毫须鼠管输入法 联想词组滤镜配置包.zip 下载取用。
如果你可以访问gitHub
,你也可以在 dyyRime 中找到完全版本的配置包。
文章分享了一种在rime
中州韵小狼毫须鼠管输入法中配置联想词组滤镜的方法。通过分别在phraseExt commonPhrase.txt
、phraseExt esAppEmoji.txt
、phraseExt esUnicode.txt
、phraseExt personal.txt
四个文档中分类整理定义了不同的联想词组,然后在phraseExt_Filter.lua
、phraseExt_Module.lua
两个脚本文档中实现了phraseExt_Filter
滤镜功能。最后以五笔・拼音输入方案为例,展示了如何在 五笔・拼音 输入方案中配置使用 phraseExt_Filter
滤镜的方法,最实现了预期的功能效果。