2025-01-06    2025-01-14    48195 字  97 分钟

说是“输入法那些事儿”,其实主要就是 Rime 那些事儿。商业输入法不怎么用,也就没有什么太多好说的,不过做为参照物可能会略有提及。

:: 目前可以看成是 Rime Home Wiki 的汇总。 – 🤣 好嘛,经过两三天的噼里啪啦,终于整合在了一起。原 Wiki 毕竟是 wiki ,内容有些凌乱,后续有时间再慢慢整理、删减、补充吧。

TODO

Rime 佛振的序

认识 La Rime。

自序

做这个项目是发自对输入法创新的兴趣,为实验新的输入法而打造一款易于定制的智能输入软件。实现好用的方言拼音输入,也是开发这款软件主要的目标。

乃定名为:中州韻輸入法引擎 / Rime Input Method Engine

取义历史上通告的中州韵,愿写就一部汇集音韵学智慧的输入法经典之作。

项目网站设在  http://rime.github.io/

感谢 Github ,感谢 Pages。

创造应用价值是一方面,更要坚持对好技术的追求,希望能写出灵动而易于扩展的代码,使其成为一款修改十足的开源输入法。

历史

2009 年底,佛振按这一思路,借助强大的 IBus 输入法框架和 Python 脚本语言,快速开发出「中州韵」的原型。 2010 年,将这一算法引擎由 Linux 移植到 Windows 平台。 几大方言社区的输入法爱好者创作了粤语、吴语、中古音输入方案,竟做到了用曾经梦想的方式打字。

如今有许多朋友关注并乐於帮忙完善这一软件。俺打盘接受同学们的建议用 C++来写一部正式版。

概念

相对于最初的实验品,概念没有多大变化。佛振重新来归纳。

组成这个软件系统的对象,我给他粗略分成三类: 逻辑对象、数据对象、交互对象

❶ 逻辑对象

逻辑对象,各自表达解决输入法中某类问题的算法,以及描述输入法的工作流程。

咱假定,从不同种类的输入法中,可归纳出几种类型的实现机制,即通用于一类输入法的算法和数据结构。

输入法引擎/engine 佛振把他解读为用来实现输入功能的程序,是这些算法及相关数据结构的总和。

输入法典型的工作流程,大致如此:

  • 获取并解释按键动作,每个按键包含键值、按键的状态等信息;
  • 生成、分析按键序列,形成编码串;某些按键并非直接產生编码字符,而有时组成输入串的文字不是按键所对应的字符本身;
  • 查字典,取得输入码对应的同码字词列表;合并、排序……
  • 有时,根据策略需要进一步组词造句;
  • 可能会对结果做出场前的修饰处理,如繁简转换等;
  • 至此,完成了从输入码到文字的翻译,结果是一组将在输入法介面展现的候选文字;
  • 用户确认,文字上屏,完成了一次输入。

将这一流程中纯粹的逻辑部份用程序写出来,就是我所形容的输入引擎。

其中不包括:

  • 实现编码到文字转换的字典数据,许多方家称「码表」;
  • 经过操作系统与设备和输入目的程序交互的组件;
  • 展现输入法信息的界面;
  • 配置工具。

❷ 数据对象

输入法中的数据对象,有输入引擎处理用户输入动作所得的动态数据,又有预先配置到输入法中的输入方案。

若要讲,输入引擎是跨输入法的通用程序,输入方案/schema 即是那差异的部份。 输入法引擎配置了不同的输入方案,便是用户视角下、统一框架内的不同输入法。 输入方案按一定的规格撰写,用户可於需要时导入到软件,这便是本项目软件开发者与输入方案创作者分工、协作的方式。

输入方案包含:

  • 配置信息,控制着输入引擎的行为;
  • 字典(码表),定义了编码与候选文字的对应关系。

为了足够灵活而能支持广泛的输入法类型,在输入方案中,利用 拼写运算/spelling algebra 机制在输入码与字典编码之间建立一组映射,以此将个别方案中的特殊检索方式统一到通用的算法。

❸ 交互对象

交互对象,承担与用户交换信息的功能。不同於输入引擎、输入方案的跨平臺特点,交互对象的实现是系统相关的。 具体地有,输入法框架通过操作系统与输入设备、输入目标程序通信;输入法介面显示输入法的状态和输入内容。

项目构成

于是整个工程又可分为若干子项目:

  • librime-输入法引擎;
  • ibus-rime-Linux 发行版;
  • weasel/小狼毫-Windows 发行版;
  • squirrel/鼠须管-Mac 发行版;
  • plum/东风破-配置管理器及输入方案仓库;
  • essay/八股文-预设词典及语言模型。

开发计划

伟大雄图,还是分期来完成吧。

初创期,完成软件架构和基础功能。

第一期,要把用户体验做到一款正式產品的标準。

  • 易用性:操作方式简明,有文档,有配置工具
  • 性能和稳定性:适应主流配置+日常应用场景
  • 输入效果:优於传统的码表输入法平臺,达到开源输入法的平均水平

第二期,兼容更多系统平台。可以尝试一些创新的设计,形成开发者暨输入方案创作者社群。

第三期,添加网络功能,持续优化输入效果;建立输入法创作平臺。

计划於八月初八发表 1.0 版。即完成初创期,进入第一期的初级阶段。

万事开头难,虽然实验版的经验可做参考,让这项目高速运转起来,仍需要大的智慧。

有同学索要文档,却真的没有。千头万绪,未及梳理,暂且概说一番,也可意会创作此软件的思路。

是为之序。

说明书📖

❶ 专题:

❷ 第三方文档

❸ 使用方案选单

下载、安装完成后,试试:

切换到 Rime 输入法,按 F4 键或组合键 Ctrl+ 唤出输入方案选单( 键常见於 1 的左方)。这里有 Rime 输入法最常用的选项。

您可立即从方案选单切换到已经启用的输入方案。

另见:从 Rime 输入方案仓库 获取输入方案

如果需要启用其他已安装的方案,或自定义方案,请……

❹ 输入法设定

——参阅《定製指南》,从中瞭解如何自定义方案选单、每页候选个数等全局选项;修改界面外观;以及调整输入方案的工作方式如指定选字、换页的按键、标点符号映射等。

目前仅【小狼毫】配有一组简单的设定面板,包含输入方案选单设定、界面风格设定、用户词典管理。其他发行版可通过修改配置文件后重新部署的方式来定製。

打字入门

以下操作多数是可定製的,此说明书以默认配置为準。

❶ 选字与换页

使用 ↑↓键 定位高亮的候选字,以空格键确认。

在【语句流】风格的输入方案里,以空格键确认后,字词并不立即上屏,而是在输入了句末的标点(,。?!等)或按下回车键(Return)时整个句子上屏。

通常,按数字键可选择序号为该数字的候选;但某些输入方案会以其他按键代替数字键,如【注音】以大写字母选字。

除了可用标準的 Page UpPage Down 换页之外,大多数输入方案里还设置了以下几组等效的换页键:

  • Shift+TabTab
  • 符号键 - =
  • 符号键 , .

❷ 令输入码直接上屏

输入编码后,如果不需要候选字而是希望输入码对应的键盘字符直接上屏,可使用回车键(Return)。

注意:【语句流】输入方案不适用。在【语句流】模式下,先按左 Shift 键切换为西文编码,再按回车键确认。

若要输出经过变换的输入码,如带声调的地球拼音、注音符号、仓頡字母等,请在输入编码后按 Shift+回车键Control+回车键

❸ 使用编辑键

使用 ←→ 键 定位光标插入点「‸」(或显示为「›」),编辑输入码。 也可用来缩短后选词所对应输入码的范围、确认词句的一部分。

HomeEnd 键 快速跳至句首、句末。

BackSpaceDelete 键 分别删除光标前、后的编码字符。注意在苹果键盘上前者标註为 Delete,后者通常是组合键 Fn+Delete

Escape 键 清空未完成的输入。

❹ 删除误上屏的错词

不慎上屏了错误的词组,再打同样的编码时,那错词出现在候选栏,令有洁癖的同学十分不爽。这时候可以:

先把选字光标(用上、下键)移到要删除的用户词组上,再按下 Shift+DeleteControl+Delete(苹果键盘用 Shift+Fn+Delete)。

只能够从用户词典中删除词组。用於码表中原有的词组时,只会取消其调频效果。

❺ Emacs 风格的编辑键

註:Windows 版本 Alt 组合键不可用。

↑:Control+p
↓:Control+n
←:Control+b
→:Control+f
上页:Alt+v
下页:Control+v
句首:Control+a
句末:Control+e
回退:Control+h
删除:Control+d
清空:Control+g
删词:Control+k

❻ 输入标点符号

按键到标点符号的映射有三种形式:

  • 按键对应惟一的符号,按键后直接输出该符号,如「,」
  • 按键对应一组配对的符号,符号交替出现,如「“”」
  • 按键对应多种符号,按键后展现选单。此时可按空格键或回车键确认高亮的符号,反复按该键则选中下一种符号。

每一款输入方案,都可以定义两套符号表,以「方案选单」里的选项「半角←→全角」往复切换。

❼ 中西文切换

打开「方案选单」,使用选项「中文←→西文」可在两种转换状态间往复切换。

此外,默认可用左右 Shift 键快速切换。

在输入了部分编码的情况下,左 Shift 将这些编码临时转还为西文。编辑临时转换的西文并以回车键上屏后,自动回复中文状态。

在输入了部分编码的情况下,右 Shift 将上屏当前的候选字,并进入西文模式。

以上可总结为:左 Shift 切换输入法光标左面的编码内容,右 Shift 切换光标右面即将输入的内容。

注意:Mac 系统上的鼠鬚管不能区分左、右 Shift ,因此左、右 Shift 键的作用一样。

❽ 繁简字切换

Rime 输入法词库多以传统汉字编排。

因为有 OpenCC 提供準确而高效的繁→简转换功能,大多数输入方案都可以从「方案选单」里选择「汉字←→汉字」的选项来启用或停用繁简转换。

码表为简化字的方案如【五笔】、【袖珍简化字拼音】等,不提供这个选项。

部分输入方案的用法

❶ 朙月拼音

与时下流行的拼音输入法相近。默认安装后将使用此方案。 其词典包含 Rime 内置的【八股文】繁体词库。设有繁简转换的开关。

~ 键开始用 hspnz 输入五笔画(横竖撇捺折),反查五笔编码。需要安装【五笔画】以启用反查。

以下有若干输入方案衍生自朙月拼音,如【语句流】、各式双拼、【宫保拼音】。还有不少方案使用朙月拼音作反查码。

《定製指南》提供了模糊音定製方法及代码模板。

❷ 语句流

揉合了语句输入的按键习惯,以及词组输入逐词确认的操作节奏。

句中空格键的运用,既起到明确词边界、弥补长句转换精度不足的作用,又很好地模仿了西文以空格断词的惯用法。

配合 Mac、IBus 版本内嵌预编辑文字的特性,体验更佳。

❸ 双拼

基於【朙月拼音】製作了几种流行的双拼方案:自然码、MSPY、智能 ABC、小鹤双拼、拼音加加等。

双拼与【朙月拼音】、语句流输入方案共用一份码表和用户词典。

实现双拼的关键,是用 Rime 的「拼写运算」技术建立双拼输入码到全拼的映射表,从而对接朙月拼音词典。在《输入方案设计书》中有一个完整的代码示例。

❹ 宫保拼音

仍是基於【朙月拼音】,採用源自西方速录技术的多键并击方式,双手共七指操作键盘,一击输入一个拼音音节。

宫保拼音 / Combo Pinyin 自从 2007 年创製以来,经歷十数次修订,孜孜以求一套直观易用,并且兼顾 PC 键盘上操作舒适度的键位佈局。

宫保拼音专题介绍

❺ 地球拼音

支持标註声调的拼音输入法。

以形似的符号 - / < \ 附加在拼音音节的末尾,分别表示阴平、阳平、上声、去声。轻声不标。

为按键方便故,也可使用 ; / , > 来标註。

声调、韵母在输入常用短语时可以省略,而成为简拼。因此本方案既兼容了无声调拼音输入法的打字习惯,又可在输入生僻字词时通过输入声调筛选出同音同调者。

因为对应相同的音系,【地球拼音】与【注音】共享词典,却不与【朙月拼音】相通。

❻ 注音

注音符号输入法。使用最广泛的「大千式」键盘排佈。

但其操作层面不同於传统的注音输入法,而是採取「无模式」的设计,与 Rime 里的其他输入方案达成统一。 所谓「无模式」,是指输入注音码,会即时显示出候选字,而不似传统的注音输入法需要另行呼出选字窗口。

Rime【注音】输入方案,允许省略声调(包含作为第一声的空格键)以及某些音节(非零声母且声母不能自成音节者)的韵母部分。 当省略声调时,可连续输入后一个音节,或间以隔音符号「 ’ 」表明前一音节结束。

此外,【注音】採用了语句流的按键习惯,以回车键确认上屏;在输入了声调的音节后,以空格键选定高亮的字词。

为了在输入注音码的同时展现候选字,候选的序号改为大写字母 ABCDE 等,以避开定义为注音符号的数字键。 要选用当页第二个候选字,可按↓键、再按空格键选定第二字,又可按下 Shift+B 键直接选取。

一些标点符号由於所在按键用作输入注音符号的原因而有所调整:

  • 逗号, Shift+,
  • 句号。 Shift+.
  • 分号; Shift+;
  • /号 Shift+/
  • 减号 Shift+- 规则很简单:符号键被注音字母佔用时,加打上档键 Shift 从符号列表中选取。

❼ 仓頡

第五代仓頡输入法。

默认,通过仓頡码检出的候选字限制在「通用字符集」,排除了 Unicode CJKV 扩展区汉字。

需要输入大量古字、生僻字的专业用户,请在「方案选单」中切换一次形如「通用 → 增广」的字符集过滤开关,即可输入七万餘简繁汉字。

註:您的系统可能需要安装专门的字体方可正确显示汉字全集。参考《定製指南》为 Rime 输入法设定用於显示候选文字的字体。

以拼音输入单字、常用词组,可反查仓頡码。需要安装【朙月拼音】以启用反查。仓頡码与拼音重码时,仓頡码查到的候选字优先。 亦可按引导键 ~ 进入拼音反查。

看到候选字一旁有「阴阳鱼 ☯」记号?

:-D 这表示,该候选词组并不存在於码表中,而是通过「混元编码器」產生、或由已知字码自动组合而成的结果。您需要确认一下这是否恰是你想要的词。 Rime 的后续版本将不断改进算法,在输入码未命中码表时,推测出更有意义的文字,越来越「懂我心意」。

❽ 速成

取仓頡首尾二码,简单快速地连续输入词、句,且支持仓頡全码、速成码混合输入。编码虽是基於字形,智能组词、调频等特性与拼音输入法别无二致。

❾ 五笔

五笔字型 86 版。简化字优先,兼收繁体字。包含小规模的词库。

敲 z 键开始转为简体拼音字词输入,反查五笔编码。需要安装【袖珍简化字拼音】以启用反查。

另有【五笔·拼音】混合输入的方案。在这款方案里,可直接以五笔或拼音码输入字、词而无须转换。输入拼音码时,若候选字、词编入了五笔码表,则在候选字一旁提示其五笔码。

❶⓿ 粤拼

以「香港语言学学会粤语拼音方案(粤拼)」输入广府话。

敲引导键 ~ 之后,开始输入汉语拼音(普通话)反查粤拼。需要安装【朙月拼音】以启用反查。

输入不完整的粤拼编码、或当拼写错误被自动纠正时,候选字、词加註完整的粤拼编码提示。 (注意:由於码表并未全部经过人工校对,程序自动注音的结果可能使提示中多音字的标註出现错误!请不要把输入法的提示当作标準学习而受误导!)

❶❷ 吴语

以「吴语拉丁式注音法」输入上海话、苏州话。

敲引导键 ~ 之后,开始输入汉语拼音(普通话)反查吴语拼写。需要安装【朙月拼音】以启用反查。

《定製指南》提供了模糊音定製方法及模板。

用户词典管理

从【小狼毫】开始菜单或托盘图标的右键菜单中打开「用户词典管理」介面。

左侧列表为已使用的用户词典,以词典名表示,如 luna_pinyin 。 注意词典与输入方案可能是一对多的关系。

❶ 命令行工具

【中州韵】和【鼠鬚管】暂无图形工具,可取得 librime 编译產出的工具程序 bin/rime_dict_manager 通过命令行方式实现以下功能。

执行 rime_dict_manager 之前需要关闭正在使用的输入法,释放以独佔方式打开的词典文件。

请,将工作目录设为「Rime 用户资料夹」。在此执行 rime_dict_manager 查看所支持的参数及命令格式;加上参数 –list 查看用户词典列表。

❷ 备份及合併词典快照

Rime 输入法在使用中会在一定时间自动将用户词典备份为快照文件 *.userdb.txt 。 也可使用管理工具,备份指定的用户词典到快照文件。

备份到快照中的打字习惯,可回复到新建立的或其他系统上的用户词典。

执行合併词典快照操作,只须选定要合併的 .userdb.txt 文件,因为快照中已记录了所属词典的名称。

你不必担心来自快照的词条已存在於用户词典的情况;词频更新为二者的较大值,其他参数亦会按照合理的算法叠加。

❸ 导出及导入文本码表

将用户词典导出为文本码表,便於直接阅读,或批量添加词条到 *.dict.yaml 。

导出的文本格式与 Rime 静态码表的格式相同:以製表符(Tab)分隔的三列,分别是文字、编码、使用频次。其中,编码是码表中定义的完全形式,多个音节间以空格。

如此导出的文本码表,可反向导入到指定的用户词典。但是,文本码表所含信息不如快照全面,因此为了不损失输入效果,请儘量使用 合入快照 的方式转移用户资料。

由於文本码表用户可以编辑,导入时无法检查码表内容是否与选定的词典相匹配,请 当心 莫要导入到错误的词典中去了。

❹ 导入其他来源的码表

推荐的作法是,将码表导入到固态词典,而非用户词典。

请参考以下两个示例:

https://gist.github.com/lotem/5443073

https://github.com/rime-aca/dictionaries

特别地,如果要用新码表的内容完全取代原有的 luna_pinyin 词典,则无须以上步骤: 将编写好的新词典命名为 luna_pinyin.dict.yaml 放置於 Rime 的「用户文件夹」,重新部署即可。

如果你认定要将码表导入已存在的用户词典,则要注意:

  • 码表文件的格式是否 Rime 所要求的 UTF-8 (no BOM) 编码
  • 文本行是否为製表符分隔,至少有文字、编码两列,及一列可选的频次
  • 文字的字形(繁、简字)是否与源码表一致
  • 编码的形式是否源码表中定义的标準形式

第一点,有一臺专业的文本编辑器就控制住啦。比如 VIM 里面用命令

:set fenc=utf8 nobomb ff=unix

转换、保存文件就中啦。

第二点,如果来源文件的资料格式不同,就需要藉助 regex 批量替换的操作,或写脚本来完成转换。

只有词条、没有编码?请重新考虑先时我提出的建议。因为,製作固态词典,可以利用【八股文】,以及自动编码器。

第三点,如果字形与目标词典不一致,推荐用 OpenCC 完成码表的繁、简转换。

第四点,凡是编码为源码表中未出现过的形式,如通过「拼写运算」实现的简拼、异拼,又如编码中的拼写错误,都将导致该条记录成为用户词典中的无效数据,因为无法通过正常的输入检索到。

❺ 同步用户资料

藉助移动存储设备,或在线存储服务如 Dropbox,在多臺电脑及不同系统之间同步用户词典和用户设定。

¹ 设定同步位置

默认地,词典快照备份到 RIME 用户文件夹\sync\UUID 这个地方。如果你要用 Dropbox 或 U 盘在不同机器/系统之间同步用户词典,则需要设定同步的目标文件夹,如 D:\Dropbox\RimeSync

直接编辑用户文件夹下的 installation.yaml ,添加:

sync_dir: 'D:\Dropbox\RimeSync'

又如 Mac 上添加:

sync_dir: '/Users/fred/Dropbox/RimeSync'

又如使用 USB 存储来同步:(真实案例)

sync_dir: '/Volumes/USBDRIVE/RimeSync'

默认地,每套 Rime 会随机生成一个 UUID 作为标识。不同 installation ID 可区分来自不同机器/系统的用户词典。

与安装在其他系统上的 Rime 同步后,同步文件夹呈如下佈局:

D:\Dropbox\RimeSync\id-xxx\luna_pinyin.userdb.txt
D:\Dropbox\RimeSync\id-xxx\terra_pinyin.userdb.txt
D:\Dropbox\RimeSync\id-xxx\installation.yaml
D:\Dropbox\RimeSync\id-xxx\default.custom.yaml
D:\Dropbox\RimeSync\id-xxx\weasel.custom.yaml

D:\Dropbox\RimeSync\id-yyy\terra_pinyin.userdb.txt
D:\Dropbox\RimeSync\id-yyy\installation.yaml
D:\Dropbox\RimeSync\id-yyy\default.custom.yaml
D:\Dropbox\RimeSync\id-yyy\squirrel.custom.yaml

D:\Dropbox\RimeSync\id-zzz\luna_pinyin.userdb.txt
D:\Dropbox\RimeSync\id-zzz\installation.yaml
D:\Dropbox\RimeSync\id-zzz\alternative.yaml
D:\Dropbox\RimeSync\id-zzz\luna_pinyin.custom.yaml

同步时,依次将各子文件夹中的词典快照合併到用户词典,最后为合併后的用户词典生成一份新的快照文件。 另外,还会把用户文件夹中非自动生成的 YAML 文件及 .txt 文件单向 备份 到同步文件夹。

有些特别讲究命名的用家,不喜随机生成的 UUID,可编辑 installation.yaml ,取一个有意义的 ID,如:

installation_id: 'fred-win7-desktop'

又如:

installation_id: 'fred-macbook'

当心!因为 Rime 要以这个 ID 为名创建文件夹,因此 ID 不得包含(所有涉及同步的文件系统)文件名中非法的字符;建议不要用中文,只用小写字母、数字、横线和下划线。

Rime 输入方案

Rime 是什么呢? Rime 不是一种输入法。它是从各种常见键盘输入法中提炼出来的抽象的输入算法框架。因为 Rime 涵盖了大多数输入法的「 共性 」,所以在不同的设定下,Rime 可以化身为不同的输入法来打字。

Rime 输入法方案又是什么?

要让 Rime 实现某种具体输入法的功能,就需要一些数据来描述这些输入法以何种形式工作。即,定义该输入法的 「 个性 」。

如 「 汉语拼音、注音、仓颉码、五笔字型 」,这些方法可凭借 Rime 提供的通用设施,给定不同的工作参数来实现。以本文介绍的规格写成一套套的方案,就是 Rime 输入方案。

文本为王。 Rime 的配置文件、输入方案定义及词典文件,均为特定格式的文本文档。Rime 中所有文本文档,均要求以 UTF-8 编码,并建议使用 UNIX 换行符 LF

鉴于一些文本编辑器会为 UTF-8 编码的文件添加 BOM 标记,为防止误将该字符混入文中,不要从文件每一行开始正文,而应该在该行行首以 # 符号起一行注释。如:

1
2
3
# Rime default settings
# Rime schema: My First Cool Schema
# Rime dictionary: Lingua Latina

也可继续以注释行写下方案简介、码表来源、制作者、个性记录等信息,再切入正文。

必知必会

Rime 输入法中,多用扩展名为 .yaml 的文本文档,这是以一种可读性高的数据描述语言 YAML 写成。

你可以访问 YAML文档 了解 YAML 文档格式。正文只对部分语法作简要说明,而将重点放在对语义的解读上面。

Rime 输入方案亦会乃至正则表达式实现一些高级功能。它采用 Perl 正则表达式语法,了解更多 Perl 正则表达式

Rime 中的数据文件分布及作用

除程序文件以外,Rime 还包换多种数据文件。这些数据文件存在于以下位置:

共享文件夹

  • 【中州韵】 /usr/share/rime-data/
  • 【小狼毫】 "安裝目錄\data"
  • 【鼠须管】 "/Library/Input Methods/Squirrel.app/Contents/SharedSupport/"

用戶文件夹

  • 【中州韵】 ~/.config/ibus/rime/ (0.9.1 以下版本为 ~/.ibus/rime/;fcitx5 为 ~/.local/share/fcitx5/rime/
  • 【小狼毫】 %APPDATA%\Rime
  • 【鼠须管】 ~/Library/Rime/

共享文件夹包含预设输入方案的源文件。这些文件属于 Rime 所发行软件的一部分,在访问权限控制较严格的系统上对用户是只读的,因此谢绝软件版本更新以处的任何修改 – 一旦用户个性这里的文件,很可能影响后续的软件升级或在升级时丢失数据。

部署 操作时,将用到这里的输入方案源文件、并组合用户定制的内容来编译预设输入方案。

用户文件夹 则包含为用户准备的内容,如:

  • 〔全局设定〕 default.yaml
  • 〔发行版设定〕 weasel.yaml
  • 〔预设输入方案副本〕 <方案标识>.schema.yaml
  • ※〔安装信息〕 installation.yaml
  • ※〔用户状态信息〕 user.yaml

编译输入方案所产出的二进制文件:

  • 〔Rime 棱镜〕 <方案标识>.prism.bin
  • 〔Rime 固定词典〕 <词典名>.table.bin
  • 〔Rime 反查词典〕 <词典名>.reverse.bin

记录用户写作习惯的文件:

  • ※〔用户词典〕 <词典名>.userdb/ 或 <词典名>.userdb.kct
  • ※〔用户词典快照〕 <词典名>.userdb.txt<词典名>.userdb.kct.snapshot 见于同步文件夹

以及用户自己设定的:

  • ※〔用户对全局设定的定制信息〕 default.custom.yaml
  • ※〔用户对预设输入方案的定制信息〕 <方案標識>.custom.yaml
  • ※〔用户自制输入方案〕及配套的詞典源文件

注:以上标有 ※ 号的文件,包含用户资料,在清理文件時要注意备份!

共享文件夹

存放由本机多个用户共享的文件,通常由输入法安装程序写入。

Rime 输入法在查找一项资源的时候,会优先访问 用户文件夹 中的文件。 用户文件不存在时,再到共享文件夹中寻找。

一些 Linux 发行版可由 rime-data 软件包安装常用数据文件到这里。或用 /plum/ 编译安装。

❶ 位置

librime 允许输入法指定共享文件夹的位置。

  • 小狼毫: <安装目录>\data
  • 鼠鬚管: "/Library/Input Methods/Squirrel.app/Contents/SharedSupport"
  • ibus-rime, fcitx-rime: /usr/share/rime-data (编译时可配置)

❷ 内容

输入方案、韵书、默认配置源文件:

  • <输入方案代号>.schema.yaml: 用户下载或自定义的 输入方案。
  • <韵书代号>.dict.yaml: 用户下载或自定义的 韵书。
  • <词典名称>.txt: 文本格式的词典,如预设词汇表。

也可以包含编译后的机读格式,从而省去用户部署时从相同源文件再次编译的步骤:

  • build/* 快取文件。为使输入法程序高效运行,预先将配置、韵书等编译为机读格式。

註: librime 1.3 版本之前,编译后的快取文件直接存放在共享文件夹,与源文件并列。

其他:

  • opencc/* - OpenCC 字形转换配置及字典文件。

用户文件夹

Rime 从「用户文件夹」读取用家自订的配置。

输入法运行时保存的数据如 用户词典、安装信息、选项状态等也放在这里。

❶ 位置

librime 允许输入法指定用户文件夹的位置。

用户文件夹的位置应使用绝对路径。请勿使用相对路径。

  • 小狼毫: 用户文件夹的默认路径为 %APPDATA%\Rime。也可以通过「开始菜单\小狼毫输入法\用户文件夹」打开。
  • 鼠鬚管: 用户文件夹的路径为 ~/Library/Rime。也可以通过「系统输入法菜单/鼠鬚管/用户设定…」打开。
  • ibus-rime: ~/.config/ibus/rime
  • fcitx-rime: ~/.config/fcitx/rime
  • fcitx5-rime: ~/.local/share/fcitx5/rime/

❷ 内容

用家下载或定製的文件:

  • <输入方案代号>.schema.yaml - 用户下载或自定义的 输入方案。
  • <韵书代号>.dict.yaml - 用户下载或自定义的 韵书。
  • <词典名称>.txt - 文本格式的词典,如预设词汇表、用户 自定义词组。
  • <配置代号>.custom.yaml - 应用於配置文件 <配置代号>.schema.yaml<配置代号>.yaml 的 补靪。
  • opencc/* - OpenCC 字形转换配置及字典文件。

输入法程序记录的使用习惯等信息:

  • <输入法语言代号>.userdb/ - 输入法程序为保存用户的输入习惯而创建的 用户词典。
  • installation.yaml - 安装信息。输入法程序在首次运行及升级后写入安装、升级时间、程序版本等。
  • user.yaml - 用户状态信息。包括在 方案选单 选取的输入方案、输入法选项状态如「中/西」「简/繁」等。

部署时生成的文件:

  • build/* - 快取文件。为使输入法程序高效运行,在部署过程中将配置、韵书等编译为机读格式。
  • trash/* - 失效的文件。因 Rime 升级而不再使用的旧文件会自动移入这个文件夹。用家确认不再需要后可以删除。

註:librime 1.3 版本之前,编译后的快取文件(包括应用了补靪的 YAML 配置)直接存放在用户文件夹;librime 升级后将其移入 trash/。如果某个 YAML 源文件已经找不到了,无法在升级后重新编译,可以从 trash/ 里面找回一份副本。

详解输入方案

想要了解更多更全面吗? 雪齐的文档  全面而详细解释了输入方案及词典中各项设定各设定项的含义及用法。

方案定义

一套输入方案,通常包含 「 方案定义 」和 「 词典 」文件。

方案定义,命名为 <方案标识>.schema.yaml,是一份包含输入方案配置信息的 YAML 文档。

文档中需要有这样一组方案描述:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 以下代码片段节选自 luna_pinyin.schema.yaml

schema:
  schema_id: luna_pinyin
  name: 朙月拼音
  version: "0.9"
  author:
    - 佛振 <chen.sst@gmail.com>
  description: |
        Rime 预设的拼音输入方案。

首先来为方案命名。schema/name 字段是显示在 〔 方案选单 〕中的名称。

然后,重点是要定一个在整个 Rime 输入法中唯一的「 方案标识 」,即 schema/schema_id 字段的内容。方案标识由小写字母、数字、下划线构成。仅于输入法内部使用,且会构成方案定义文件名的一部分,因此为了兼容不同的文件系统,不要用大写字母、汉字、空格和其他符号做方案标识。如:这款名为〔 朙月拼音 〕的输入方案,方案标识为 「 luna_pinyin 」。

方案如做升级,通过版本号 schema/version 来区分相互兼容的新旧版本。版本号是以 . 分隔的整数或文字构成的字符串。如下都是版本号常见的形式:

"1"      # 最好加引号表明是字符串!
"1.0"    # 最好加引号表明是字符串!
"0.9.8"
"0.9.8.custom.86427531"  # 这种形式是经过用户自定义的版本:自动生成

然而,若对方案的升级会导致原有的用户输入习惯无法在新的方案中继续使用,则需要换个新的方案标识。

比如仓颉五代之于仓颉三代,五笔 98 之于五笔 86,其实已是互不兼容的输入法。

schema/author ——列出作者和主要贡献者,格式为文字列表:

1
2
3
4
5
schema:
  author:
    - 作者甲 <alpha@rime.org>
    - 作者乙 <beta@rime.org>
    - 作者丙

schema/description ——对方案作简要介绍的多行文字。

以上 schema/schema_idschema/version 字段用于在程序中识别输入方案,而 schema/nameschema/authorschema/description 则主要是展示给用户的信息。

除方案描述外,方案定义文件中还包含各种功能设定,控制着输入法引擎的工作方式。

输入法引擎与功能组件

以下是 Rime 输入法的工作流程:

按键消息 → 后台「 服务 」 → 分配给对应的「 会话 」→ 由「 方案选单 」或「 输入引擎 」处理……

这里要点是,有会话的概念:多窗口、多线操作嘛,你懂得的,同时与好几位 MM 聊天时,有没有好几组会话。每一组会话中都有一部输入引擎完成按键序列到文字的变换。

Rime 可以在不同会话里使用不同输入方案。因为有「 方案选单 」。方案选单本身可响应一些按键。但由于它不会写字的缘故,更多时候要把按键传递给同一会话中的「 输入引擎 」继续处理。方案选单的贡献,就是给用户一个便捷的方案切换介面,再把用户挑中的输入方案加载到输入引擎。

让我们看一下输入引擎的工作流程:

加载输入方案、预设功能组件 → 各就各位之后就进入处理按键消息、处理按键消息……的循环

响应各种按键、产生各类结果的工作,由不同的功能组件分担。

好,看代码:

 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
# luna_pinyin.schema.yaml
# ...

engine:                          # === 输入引擎设定 ===
  processors:                    # » ¹这批组件处理各类按键消息 
    - ascii_composer             # ※ 处理西文模式及中西文切换
    - recognizer                 # ※ 与 matcher 搭配,处理符合特定规则的输入码,如网址、反查等
    - key_binder                 # ※ 在特定条件下将按键绑定到其他按键,如重定义逗号、句号为候选翻页键
    - speller                    # ※ 拼写处理器,接受字符按键,编辑输入码
    - punctuator                 # ※ 句读处理器,将单个字符按键直接映射为文字符号
    - selector                   # ※ 选字处理器,处理数字选字键、上、下候选定位、换页键
    - navigator                  # ※ 处理输入栏内的光标移动键
    - express_editor             # ※ 编辑器,处理空格、回车上屏、回退键等
  segmentors:                    # » ²这批组件识别不同内容类型,将输入码分段 
    - ascii_segmentor            # ※ 标识西文段落
    - matcher                    # ※ 标识符合特定规则的段落,如网址、反查等
    - abc_segmentor              # ※ 标识常规的文字段落
    - punct_segmentor            # ※ 标识句读段落
    - fallback_segmentor         # ※ 标识其他未标识段落
  translators:                   # » ³这批组件翻译特定类型的编码段为一组候选文字 
    - echo_translator            # ※ 没有其他候选字时,回显输入码
    - punct_translator           # ※ 转换标点符号
    - script_translator          # ※ 脚本翻译器,用于拼音等基于音节表的输入方案
    - reverse_lookup_translator  # ※ 反查翻译器,用另一种编码方案查码
  filters:                       # » ⁴这批组件过滤翻译的结果
    - simplifier                 # ※ 繁简转换
    - uniquifier                 # ※ 过滤重复的候选字,有可能来自繁简转换

注:除示例代码中引用的组件外,尚有

1
2
3
- fluid_editor      # ※ 句式编辑器,用于以空格断词、回车上屏的「 注音、语句流 」等输入方案,替换 express_editor,也可以写作 fluency_editor
- chord_composer    # ※ 和弦作曲家或曰并击处理器,用于「 宫保拼音 」等多键并击的输入方案
- table_translator  # ※ 码表翻译器,用于仓颉、五笔等基于码表的输入方案,替换 script_translator

输入引擎把完成具体功能的逻辑拆分为可装卸、组合的部件。「 加载 」输入方案,即按该处方挂接所需的功能组件、令这些组件从输入方案定义中加载各自的设定、准备各司其职。而他们接下来要完成作业,由引擎收到的一份按键消息引发。

理解 Processors

输入引擎,作为整体来看,以按键消息为输入、输出包括三部分:

  1. 对按键消息的处理结果:操作系统要一个结果、这按键、输入法接是不接?
  2. 暂存于输入法、尚未完成处理的内容,会展现在输入法候选窗中;
  3. 要「 上屏 」的文字,并不是每按一键都有输出。通常中文字都会伴随「 确认 」动作而上屏,有些按键则会导致符号上屏,而这些还要视具体场景而定。

那么第一类功能组件 processor s ,就是比较笼统地、起着「 处理 」按键消息的作用。

按键消息依次送往列表中的 processor,由他给出对按键的处理意见:

  • 或曰「 收 」,即由 Rime 响应该按键:
  • 或曰「 拒 」,即回答操作系统 Rime 不做响应、请对按键做默认处理;
  • 或曰这个按键我不认得、请下一个 processor 继续看。

优先级依照 processors 列表顺序排定,接收按键者会针对按键消息做处理。

虽然看起来 processor 通过组合可以承担引擎的全部任务,但为了将逻辑继续细分、Rime 又为引擎设置了另外三类功能组件。这些组件都可以访问引擎中的数据对象 – 输入上下文,并将各自所做处理的阶段成果在于其中。

processor 最常见的处理,便是将按键所产生的字符废上下文中的「 输入码 」序列。当「 输入码 」发生变更时,下一组组件 segmentor s 开始一轮新的作业。

理解 Segmentors

Segment 是段落的意思,segmentor 即 分段器,将用户连续输入的文字、数字、符号等不同内容按照需要,识别不同格式的输入码,将输入码分成若干段分而治之。这通过数轮代码段划分操作完成。每一轮操作中、一众  segmentor s 分别给出起始于某一处、符合特定格式的代码段,识别到的最长代码段为本轮划分结果,而给出这划分的一个或多个 segmentor 组件则可为该代码段打上「 类型标签 」 ;从这一新代码段的结束位置,开始下一轮划分,直到整个输入码序列划分完毕。

举例来说,「 朙月拼音 」中,输入码 2012nian\ ,划分为三个编码段:

- 2012    → 贴 number 标签 
- nian    → 贴 abc    标签
- \       → 贴 punct  标签

那些标签是初步划分后判定的类型,也可能有一个编码段贴多个标签的情况。下一个阶段中, translator s 会把特定类型的编码段翻译为文字。

理解 Translators

顾名思义, translator 完成由编码到文字的翻译。但有几个要点:

  1. 翻译是对象是划分好的一个代码段;
  2. 某个 translator 组件往往只翻译具有特定标签的代码段;
  3. 翻译的结果可能有多条,每条结果成为一个展现给用户的候选项;
  4. 代码段可由几种 translator 分别翻译,翻译结果按一定规则合并成一列候选;
  5. 候选项所对应的编码未必是整个代码段。用拼音敲一个词组时,词组后面继续列出单字候选,即是此例。

让们看一下它们在内存中的存储,发现翻译的结果呈现这种形式:

input | tag    | translations
------+--------+-------------------------------------
2012  | number | [ "2012" ], [ "二〇一二" ]
nian  | abc    | [ "年", "念", "唸",... ], [ "nian" ]
\     | punct  | [ "、", "\" ]

输入串划分为多个代码段,每段代码又可具有多级翻译结果;取各代码段的首先结果连接起来,就是预备上屏的文字「 2012年、 」。

且将以上所示的数据称为 「 作文 」。这是一篇未定稿(未搞定)的作文,输入法介面此时显示预备上屏的文字「 2012年、 」,并列出最末一个代码段上的候选「 」及「 \ 」以供选择。

有两款主力 translator 完成主要文字内容的翻译,其实现的方式很不一样:

¹ script_translator 也叫做 r10n_translator 修炼罗马字分析法,以「 固定音节表 」为算法的基础,识别输入码的音节构成,推敲排列组合、完成遣词造句。

² table_translator 修炼传承自上世纪的码表功夫,基于规则的动态码表,构成编码空间内一个开放的编码集合。

拼音、注音、方言拼音,皆是以固定音节表上的拼写排列组合方式产生编码,故适用罗马字分析法。

仓颉、五笔字型这类则是传统的码表输入法。

如果以码表方式来写拼音输入方案,是怎么的效果呢?虽然仍可完成输入,但无法完全实现运行简拼、模糊拼音、使用隔音符号的动态高频、智能语句等有用的特性。

反之,以罗马字方式使用码表输入法,则无法实现定长编码顶字上屏、按编码规则构词等功能。在 Rime 各发行版预设输入方案中,有一款「 速成 」输入方案,即是以 script_translator 翻译仓颉码,实现全、简码混合的语句输入。

概括起来,这是两种构造新编码的方式:罗马字式输入方案以一组固定的基本音节码创造新的组合而构词,而码表式输入方案则以一定码长为限创造新的编码映射而构词。

理解 Filters

Filter 即 过滤器。上一步已经收集到各个代码段的翻译结果,当输入法需要在介面呈现一页候选项时,就从最末一个代码段的结果集中挑选,直至取够方案中设定的页最大候选数。

每从结果集选出一条字词,会经过一组  filter s 过滤。多个 filter 串行工作,最终产出的结果进入候选序列。

filter 可以:

  • 改装正在处理的候选项,修改某些属性值:简化字、火星文有没有?
  • 消除当前候选项,比如检测到重复(由不同 translator 产生)的候选条目;
  • 插入新的候选项,比如根据已有条目插入关联的结果;
  • 修改已有的候选序列。

码表与词典

词典是 translator 的参考书。

它往往与同名输入方案配套使用,如拼音的词典以拼音码查字,仓颉的词典以仓颉码查字。但也可由若干编码属于同一系统的输入方案共用,如各种双拼方案,都使用和拼音同样的词典,于是不仅复用了码表数据,也可共享用户以任一款此系列方案录入的自造词(仍以码表中的形式取全拼编码记录)。

Rime 的词典文件,命名为 <词典名>.dict.yaml,包含一份码表及对应的规则说明。词典文件的前半部分为一份 YAML 文档。

1
2
3
4
5
6
7
8
# 注音这里以 --- ... 分别标记出 YAML 文档的起始与结束位置
# 在 ... 标记之后的部分就不会作 YAML 文档来解读
---
name: luna_pinyin
version: "0.9"
sort: by_weight
use_preset_vocabulary: true
...

其中:

¹ name ,词典名,内部使用,命名原则同 「 方案标识 」,可以与配套的输入方案标识一致,也可以不同。

² version,管理词典的版本,规则同输入方案定义文件的版本号。

³ sort,词条初始化排序方式,可选填 by_weight (按词频高低排序)或 original (保持原码表中的顺序)。

⁴ use_preset_vocabulary ,填 truefalse ,选择是否导入预设词汇表「 八股文 」。

码表,定义了输入法中编码与文字的对应关系。

码表位于词典文件中 YAMl 结束标记之后的部分。其格式为以制表符分隔的值,每行定义一条(文字 - 编码)的对应关系:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 单字
你	ni
我	wo
的	de	99%
的	di	1%
地	de	10%
地	di	90%
目	mu
好	hao

# 词组
你我
你的
我的
我的天
天地	tian di
好天
好好地
目的	mu di
目的地	mu di di

注音:不要从网页复制以上代码到实际的词典文件!因为网页制作符被转换成空格从而不符合 Rime 词典要求的格式。一些文本编辑器也会将使用者的制表符自动转换为空格,请注音检查和设置。

码表部分,除了以上格式的编码行,还可以包含空行及注释行(行首为 # 符号)。

¹ 以制表符(TAB)分隔的第一个字段是所定义的文字,可以是单字或词组。

² 第一个字段是与文字对应的编码。若该编码由多个音节组成,音节之间以空格分开。

³ 第三个字段(可选的)是设定该字词的权重(非负整数),或相对于预设权值的百分比(浮点数%)。在拼音输入法中,往往多音字的若干种读音使用的场合不同,于是指定不同百分比来修正每个读音的使用频率。

词组如果满足以下条件,则可以活动编码字段:

  • 词组中的每个单字均胡编码定义;
  • 词组中不包含多音字(如:你我),或多音字在该词组中的读音的权值超过该多音字全部读音权值的 5% (如:我的)。

这种条件下,词组的编码可由单字编码组合推导出来。

反之,则有必要给出词组的编码以消除自动注音的不确定性(如:天地)。

当含有多音字的词组缺少编码字段时,自动注音程序会复用权重百分比高于 5% 的读音进行组合,生成全部可能的注音。如:

「 好好地 」在编译时自动注音为 「 hao hao de 」、「 hao hao di 」。

编译输入方案

将写好的输入方案部署到 Rime 输入法的过程,称为 「 编译 」。

为了查询效率,输入法工作时不直接加载文本格式的词典源文件,而是加载编译过程中为输入方案生成的专为高速查询设计的 「 .bin 」文件。

编译时程序做以下几件事:

  • 将用户的定制内容合并到输入方案定义中,在用户文件夹生成 .schema.yaml 文档副本;
  • 依照输入方案中指定的词典:求得音节表(不同编码的集合)、单字表;
  • 对词典中未提供编码的词组自动注音,也包括从「 八股文 」导入的词组;
  • 建立按音节编码检索词条的索引,制作 Rime 固定词典;
  • 建立按词条检索编码的索引,制作 Rime 反查词典;
  • 依照音节表选方案定义中指定的拼写运算规则,制作 Rime 棱镜。

部署

初次安装 Rime 输入法,没有任何输入方案选用户设定。因此安装的最后一个步骤即是把发行版预设的输入方案选设定文件部署到 Rime 为该用户创建的工作目录,至此 Rime 组成为一部可以发动的输入引擎。

此后无论是修改已有方案的设定,或是添加了新的输入方案,都需要「 重新部署 」成功后方可使新的设定生效。

重新部署的方法:

  • 小狼毫:开始菜单 » 重新部署;或右击托盘图标 » 重新部署;
  • 鼠须管:在系统语言文字选单中选择重新部署;
  • 中州韵:点击输入法状态样(或 IBus 菜单)上的 ⟲ (Deploy) 按钮。

定制指南

Rime 输入方案,将 Rime 输入法的设定整理成完善的、可分发的形式。但并非一定要创作新的输入方案,才可以改变 Rime 的行为。

当用户需要对 Rime 中的各种设定做小幅的调节,最直接、但不完全正确的做法是:编辑用户文件夹中的那些 .yaml 文档。

这种方法有弊端:

  • 当 Rime 软件升级时,也会升级各种设定档、预设输入方案。用户编辑过的文档会被覆写为更高版本,所做高速也便丢失了;
  • 即使在软件升级后再手动恢复经过编辑的文件,也会因设定档的其他冷媒未得到更新而失去本次升级新增选修复的功能。

因此,对于随 Rime 改造的设定档及预设输入方案,⭐️ 推荐的定制方法是:

创建一个文件名的主体部分与要定制的文件相同、次级扩展名(位于 .yaml 之前)写作 .custom 的定制档,形如:

1
2
3
4
5
6
7
8
9
patch:
  "一组设定项/二级设定项/三级设定项": 新的设定值
  "另一个设定项": 新的设定值
  "再一个设定项": 新的设定值
  "含列表的设定项/@0": 列表第一个元素新的设定值
  "含列表的设定项/@last": 列表最后一个元素新的设定值
  "含列表的设定项/@before 0": 在列表第一个元素之前插入新的设定值(不建议在补丁中使用)
  "含列表的设定项/@after last": 在列表最后一个元素之后插入新的设定值(不建议在补丁中使用)
  "含列表的设定项/@next": 在列表最后一个元素之后插入新的设定值(不建议在补丁中使用)

patch 定义了一组补丁,以源文件中的设定为底本,定入新的设定项、或以新的设定值取代旧有的值。

以下这些例子,请参阅另一篇 定制指南 ,其中所介绍的知识选技巧,覆盖了不少本方未讨论的细节,想必对于创作新的输入方案会有启发。

重要!创作了新的输入方案,最后一步就是在「 方案选单 」中启用它。可以在 [[#定制指南详解]] 中了解更多。

拼写运算

i.e. Algebra

📘 拼写运算 · rime/home Wiki — SpellingAlgebra · rime/home Wiki

应该算是 Rime 输入法最主要的独创技术。

概括来说就是将方案中的编码通过规则映射到一组全新的拼写形式!也就是说能让 Rime 输入方案在不修改码表的情况下,适应不同的输入习惯。

拼写运算能用来:

  • 改革拼写法:将编码映射到基于同一音系的其他拼写法,如注音、拼音、国语罗马字相互转换;自定义注音键盘、双拼方案;
  • 实现简拼查询;
  • 在音节表上灵活地定义模糊音规则;
  • 实现音节自动纠错;
  • 变换回显的输入码或提示码,如将输入码显示为字根、注音符号、带声调标的罗马字。

给力吗?必须的。

常用术语

先来介绍本文所使用的术语:

输入法:以输入信号的序列到输出文本序列的转换方法。Rime 可搭载多种不同类型的输入法,称其为「 输入方案 」。

字符集:构成目标输出文本的字符的集合,主要由汉字组成。

编码:用于检索目标字符的字母序列。

字母:构成编码的字符,亦称「 码元 」。

字母表:字母的集合,亦称「 编码字符集 」,通常由小写拉丁字母组成。

码表:目标字符集与编码集合之间的映射表。

码长:单个编码所包含的字母个数。码表中所有编码码长一致,本文称其为「 定长编码 」。规定了最大编码的编码方案,本文称其为「 限长编码 」。

编码空间:给定的字母表以有限的码长排列组合所得的可用编码数目。

音节表:输入方案中所有编码的集合。拼音输入方案中,彼此不同的音节是可穷举的,其音节表是个固定的集合。多数形码输入法按照一定规则在给定的编码空间中为新生词组编码,故无法给出固定的音节表。

重码:对应到多个输出字符的编码。

输入码:用途输入的字符序列。

候选:与输入码相关联的目标输出文字。当有重码时,候选文字形成一个列表可供用户挑选。

拼写:与单个编码相对应的输入码。拼写可能不同于编码。

拼写法:一种输入方案里,有效拼写的集合到编码集合的映射,亦称「 正字法 」。

拼写运算:以拼写为运算元的一元运算。通过字符串匹配及替换操作对拼写实施文字变换,获得一个新的拼写,并可赋予结果附加的属性。

投影:以拼写法为运算元的一元运算,获得一个衍生的拼写法。实际运用时,通常对拼写法连续执行一组投影操作。每一轮操作中,对拼写法里的每个有效拼写做一次拼写运算,从而获得新的有效拼写集合,并重新建立其与编码集合的映射。

功能

传统的中文输入法是基于码表的,通过键盘输入特定字母序列,获得与该编码对应的文字。而大多数编码方案,都不会用尽编码空间内的所有编码。与字符集内的文字无对应的编码,就在编码空间中形成空位。为了提高输入效率,输入法会复用编码空间中的空位,编制简码、容错码等衍生编码,以在尽量多的场合为用户提供有意义的候选文字。

:: 编码空间中空位,就是没有对应文字的编码。

在某些输入方案里,简码、容错码可以从源码表按照一定规则产生。如:汉语拼音输入法中的简拼,取拼音音节的首字母,也可取以双这互表示的声母 zh、ch、sh 。这是因为 编码方案所遵循的语言学原理,决定了拼音音节在编码空间内的分布及留下的空位,呈某种规则的形式。 故,产生简码、容错码的规则是与输入方案相关的,一款通用的输入法软件要以与编码方案相适应的方式生成这些衍生编码。

拼写运算,提供了描述产生式规则的能力! 🥳

为了提供多样化的输入体验,Rime 可藉由一份码表制作多款输入方案。譬如:注意符号、汉语拼音这两套注意方案是为相同音系设计的(忽略地区间字音标准的差异)。信有一份注意码表,按一定对应规则将注意转换为汉语拼音,可使注意、汉语拼音,甚至还有基于汉语拼音的双拼等输入方案复用同一部词典。

拼写运算,提供为输入方案重构拼写法的能力! 🥳

此外,改变编码回显的样式、按特定规则生成词组编码……拼写运算也可用来实现此等需要定制能力的算法。

原理与实现 🌟

拼写运算,借助正则表达式实现其字符串处理能力。进一步,利用数学知识,构造出建立在输入法编码集合上的运算系统。

拼写运算实现为 Rime 程序库中的一套算法,可从 Rime 配置文件导入一组算式,执行规定的计算步骤。运算步骤以 YAML 字符串列表的形式定义,每个列表为描述为描述一项运算的算式。算式中包含的正则表达式,遵照 Perl 正则表达式的语法规范。

❶ 拼写运算的算式

格式为:<运算子><分隔符><参数1><分隔符><参数2><分隔符>...
如:
xlit/abc/ABC
- 运算子为 xlit(转写)
- 分隔符为 /
- 两个参数 abc 和 ABC

其中,分隔符为单个 ASCII 字符,通常用符号或空白字符。

如果参数中不包含空格,也可写作:
xlit abc ABC

注意:作为分隔符的字符不能在参数中出现。不同于 Perl 的 s///\/ 语法,拼写运算式不支持在参数中将用作分隔符的字符用 \ 转义表示。

❷ 拼写运算的运算子

¹ 转写 / Transliteration

依次将拼写中见于 <左字母表> 的字符替换为 <右字母表> 对应位置的字符。左、右字母表应包含相同数目的 Unicode 字符。

格式: xlit/<左字母表>/<右字母表>/

如:
算式   xlit/abs/ABC/ 
运算元 abracadabra
结果 → ABrACAdABrA

² 变形 / Transformation

若拼写(或其子串)与 <模式> 匹配,则将所匹配的部分改写为 <替换式>,否则拼写保持不变。模式、替换式遵循 Perl 正则表达式语法。

格式:xform/<模式>/<替换式>

如:
算式   xform/^([nl]ue$)/$1ve/
运算元 nue
结果 → nve

效果:输入 nve(lve) 可以获取码表中与编码 nue(lue) 对应的候选。输入 nue(lue) 则无候选。

:: 因为已经变形以嘛~

³ 消除 / Erasion

若拼写与 <模式> 完全匹配,则将该拼写从有效拼写集合中消除。

格式: erase/<模式>/

如:
算式   erase/^.\d$/
运算元 dang1
结果 → 带声调的拼音不再可用

⁴ 派生 / Derivation

若对拼写做正则模式匹配、替换而获得了新的拼写,则有效拼写集合同时包含派生前后的拼写,否则保留原拼写。

格式: derive/<模式>/<替换式>/

如:
算式   derive/^([nl])ue$/$1ve/
运算元 nue
结果 → nve

效果:输入 nve、nuelve、lue 均可获得源码表中与编码 nue、lue 对应的候选。

如:
算式   derive/^[nl](.*)$/l$1/
运算元 na
结果 → la

效果:输入 la 可获得源码表中与编码 na、la 对应的候选;输入 na ,候选仍为码表中编码为 na 的候选。

⁵ 模糊 / Fuzzing

执行派生运算。派生出来的拼写将获得「 模糊 」属性,可设定将其用作构成词组的简码、但不用于输入单字。

格式: fuzz/<模式>/<替换式>/

如:
算式   fuzz/^([a-z]).+([a-z])$/$1$2/

效果:以首、尾码为多字母音节码的构词码。

注:需要配合 script_translator 的选项 translator/strict_spelling: true 方可限定该拼写不用于输入单字。

⁶ 缩略 / Abbreviation

执行派生运算。派生出的拼写将获得 「 缩略 」属性,会在音节切分时与通常的拼写做区分处理。

格式: abbrev/<模式>/<替换式>

如:
算式  abbrev/^([a-z]).+$/$1/

效果:以首字母为多字母音节码的编写。


注解:

转写 是拼写运算中目前唯一一则将运算元和参数作 UTF-32 编码,而非 UTF-8 编码处理的运算。意味着,字母表可以采用 ASCII 范围以外的字符。字母表的长度按照 Unicode 字符数来计算。

转写变形 两则运算,除在拼写法投影操作中起重要作用,还可用于对单个字符串进行变换。 消除、派生缩略 用于定义拼写投影中非一一映射的情况。

消除 就给定的模式,对运算元做完全匹配,即 regex match 操作。 变形、派生缩略 则可做部分匹配,相当于 regtx search/global replace 操作。

投影算法

在拼写法投影操作 P[x,y,z] 里,每项运算 x,y,z 作为投影的一个步骤,依次从作为运算元的拼写法中产生一套新的拼写法。将拼写法投影用于构建 “拼写-编码” 映射时,用户的输入是随意的,而码表中,音节表是固定的集合 A 。

所以 Rime 选音节表 A 上的初始拼写法(A → A)为投影的运算元,逐步推导出映射到音节表 A 的有效拼写集合 B ,即所求的拼写法 (B → A)。

算法:

记音节表为 A ,拼写运算为序列 [x,y,z],该投影的结果为 P[x,y,z](A -> A)
Sa = { a -> a | for a in A } = (A -> A)
Sx = P<x>(Sa) = { x(a) -> a | for (a -> a) in (A -> A) } = (B -> A)
Sy = P<y>(Sx) = { y(b) -> a | for (b -> a) in (B -> A) } = (C -> A)
Sz = P<z>(Sy) = { z(c) -> a | for (c -> a) in (C -> A) } = (D -> A)
P[x,y,z](Sa) = Sz

在 Rime 输入方案中的用法

例¹:仓颉输入方案(cangjie5.schema.yaml),在编码区回显仓颉字母。

translator:
  preedit_format:
    - xlit|abcdefghijklmnopqrstuvwxyz|日月金木水火土竹戈十大中一弓人心手口尸廿山女田難卜符|

例²:朙月拼音(luna_pinyin.schema.yaml),显示拼音字母“ü”

translator:
  preedit_format:
    - xform/([nl])v/$1ü/

这一处,拼写运算的作用对象是编码回显区的拼音串,串中可能包含多个拼音音节,并已经自动插入了隔音符号。为了替换该拼音段中所有匹配的字母,模式中并未用锚点匹配音节的头尾位置。

例³:朙月拼音(luna_pinyin.schema.yaml),定义简拼、容错拼写。

speller:
  algebra:
    - abbrev/^([a-z]).+$/$1/          # 简拼(首字母)
    - abbrev/^([zcs]h).+$/$1/         # 简拼(zh, ch, sh)
    - derive/^([nl])ve$/$1ue/         # 设 nue = nve, lue = lve 
    - derive/ui$/uei/                 # 设 guei = gui,...
    - derive/iu$/iou/                 # 设 jiou = jiu,...
    - derive/([aeiou])ng$/$1gn/       # 容错 dagn = dang,...
    - derive/ong$/on/                 # 容错 zhonguo = zhong guo
    - derive/ao$/oa/                  # 容错 hoa = hao,...
    - derive/([iu])a(o|ng?)$/a$1$2/   # 容错 tain = tian,...

编译输入方案时,将运用这组运算规则完成音节表上的投影,求得可解析为音节代码的有效拼写集合。输入过程中,这组有效拼写决定着输入码在音节切分方式。

例⁴:在拼音输入法中定义模糊音 zh=z, ch=c, sh=s, n=l, en=eng, in=ing

speller:
  algebra:
    - derive/^([zcs])h/$1/
    - derive/^([zcs])([^h])/$1h$2/
    - derive/^n/l/
    - derive/^l/n/
    - derive/([ei])n$/$1ng/
    - derive/([ei])ng$/$1n/
    # 模糊音定义先于简拼定义,可令简拼支持以上模糊音
    - abbrev/^([a-z]).+$/$1/
    - abbrev/^([zcs]h).+$/$1/

综合演练

牛刀小试 🌟

如果你安装好了 Rime 却不会玩,就一步一步跟我学吧。

本系列课程每个步骤的完整代码可由此查阅: rimeime/doc/tutorial

¹一个简单的方案

每一个例子,总是最简单的(也是最傻的)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Rime schema - hello.schema.yaml
# encoding: utf-8
#
# 最简单的 Rime 输入方案
#

schema:
  schema_id: hello    # 注意此 ID 与文件名里 .schema.yaml 之前的部分相同
  name: 大家好        # 将在〔方案选单〕中显示
  version: "1"        # 这是文字类型而非整数或小数,如 "1.2.3"

起始行是注释,而后只有一组必要的方案描述信息。

这一课主要练习建立格式正确的 YAML 文档。

  1. 始终使用 UTF-8 格式编辑保存你的方案;
  2. 使用空格缩进(两个空格),而不是 Tab 字符。

缩进表示设定所属的层次。

缩进表示设定项所属的层次。在他处引用到此文档中的设定项,可分别以 schema/schema_idschema/nameschema/version 来指称。

我现在把写好的方案文档命名为 hello.schema.yaml,丢进用户文件夹,只要这一个文件就妥了。

然后,启用它。

有些版本会有「 方案选单设定 」这个介面,在那里勾选 「 大家好 」这个方案即可。若没有设定介面,则按照上文《定制方案选单 》一节来做。

好运!我已建立了一款名为 「 大家好 」的新方案!虽然他没有实现任何效果,按键仍然会像没有输入法一样直接输出英文。

²开始改装

为了处理字符按键、生成输入码,本例向输入引擎添加两个功能组件。

以下代码仍是 ID 为 hello 的新款输入方案,但更新了  schema/version 的数值。

以后每个版本,都以前一个版本为基础改写,引文略去没有发动的部分,以突出重点。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# ...
schema:
  schema_id: hello
  name: 大家好
  version: "2"

engine:
  processors:
    - fluid_editor
  segmentors:
    - fallback_segmentor

fluid_editor 将字符按键记入输入上下文, fallback_segementor 将输入码连缀成一段。于是重新部署后,按下字符键不再直接上屏,而是显示输入码。

你会发现,该输入法只是收集了键盘上的可打印字符,并于按下空格、回车键时信输入码上屏。

现在就好似写输入法程序的过程中,刚刚取得一点成果,还有很多逻辑没有实现。不同的是,在 Rime 输入方案里定一行代码,顶 Rime 开发者所写的上百上千行。因此键可以很快地组合各种逻辑组件,搭建出想要的输入法。

³创建候选项

在上个版本(第二版)的方案「 大家好 」中,键们实现了将键盘上所有字符都记入输入码,这对整句输入有用,但是时政流行输入法只处理编码字符,其他字符直接上屏的形式。

为了对编码字符做出区分,以下改用 speller + express_editor 的组合取代 fluid_editor

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# ...

schema:
  # ...
  version: "3"

engine:
  processors:
    - speller          # 把字母追加到编码串
    - express_editor   # 空格确认当前输入,其他字符直接上屏
  segmentors:
    - fallback_segmentor

speller 默认只接受小写拉丁字母作为输入码。试试看,输入其他字符如大写字母、数字、标点,都会直接上屏。并且如果已经输入了编码时,下一个直接上屏的字符会将输入码顶上屏。

再接着,创建一个最简单的候选项 – 把编码串本身作为一个选项。故而会提供这个选项的新组件名叫 echo_translator

1
2
3
4
5
6
# ...

engine:
  # ...
  translators:
    - echo_translator  # (没有其他结果时)创建一个与编码串一模一样的候选项

至此,「 大家好 」看上去与一个真正的输入法形似啦,只是还不会打出“大家好”这个短语哦 ?

⁴编写词典

那就写一部词典,码表中规定以 hello 作为短语“大家好”的编码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Rime dictionary
# encoding: utf-8

---
name: hello
version: "1"
sort: original
...

大家好	hello
再见	bye
再会	bye

同时修改方案定义:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#...

schema:
  # ...
  version: "4"

engine:
  #...
  segmentors:
    - abc_segmentor       # 标记输入码的类型
    - fallback_segmentor
  translators:
    - echo_translator
    - table_translator    # 码表式转换

translator:
  dictionary: hello       # 设定 table_translator 使用的词典名

工作流程是这样的:

  • speller 将字母键加入输入码序列;
  • abc_segmentor 给输入码打上标签 abc
  • table_translator 把带有 abc 标签的输入码以查表的方式翻译为中文
  • table_translator 所查的码表在 translator/dictionary 所指定的词典里

现在可以敲 hello 而打出「大家好」。完工!

⁵实现选字及换页

等一下。

记得 hello 词典里,还有个编码叫做還 bye。敲 bye,Rime 给出「再见」、「再会」两个候选短语。

这时敲空格键,就会打出 「 再见 」;那么怎么打出 「 再会 」呢?

大家首先想到的方法是,打完编码 bye ,按 1 选 「 再见 」,按 2 选「 再会 」。可是现在按下 2 去,却是上屏「 再见 」选数字 「 2 」。可见并没有完成数字键选字的处理,而是将数字同其他符号一样顶字上屏处理。

增加一部 selector,即可实现以数字键选字。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
schema:
  # ...
  version: "5"

engine:
  processors:
    - speller
    - selector         # 选字、换页
    - navigator        # 移动插入点
    - express_editor
  # ...

selector 除了数字键,还响应前次面、上下方向键。因此选择第二候选「 再会 」,既可以按数字 2 ,又可以按方向键「 ↓ 」将 「 再会 」高亮、再按空格键确认。

navigator 处理左右方向键、HOME、END 键,实现移动插入点的编辑功能。有两种情况需要用到它:一是发现输入码有误需要定位修改;二是缩小选词对应的输入码的范围、精确地编辑新词组。

接下来向词典添加一组重码,以检验换页的效果:

 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
---
name: hello
version: "2"
sort: original
...

大家好	hello
再见	bye
再会	bye

星期一	monday
星期二	tuesday
星期三	wednesday
星期四	thursday
星期五	friday
星期六	saturday
星期日	sunday

星期一	weekday
星期二	weekday
星期三	weekday
星期四	weekday
星期五	weekday
星期六	weekday
星期日	weekday

默认每页候选数为 5 ,输入  weekday,显示「星期一」至「星期五」。再敲 Page_Down 显示第二页候选词「星期六、星期日」。

⁶输出中文标点

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
schema:
  # ...
  version: "6"

engine:
  processors:
    - speller
    - punctuator        # 处理符号按键
    - selector
    - navigator
    - express_editor
  segmentors:
    - abc_segmentor
    - punct_segmentor   # 划界,与前后方其他的编码区分开
    - fallback_segmentor
  translators:
    - echo_translator
    - punct_translator  # 转换
    - table_translator

# ...

punctuator:             # 设定符号表,这里直接导入预设的
  import_preset: default

这次的修改,要注意 punctuatorpunct_segmentorpunct_translator 相对于其他组件的位置。

punctuator/import_preset 告诉 Rime 使用一套预设的符号表。它的值 default 可以换成其他名字如 xxx,則 Rime 会读取 xxx.yaml 里面定义的符号表。

如今再敲 hello. 就会得到「大家好。」

⁷用符号键换页

早先流行用 - 和 = 这一对符号换页,如今流行用 , 和 . 。 在第六版中「,」「。」是会顶字上屏的。现在要做些处理以达到一键两用的效果。

Rime 提供了 key_binder 组件,他能夠在一定条件下,将指定按键绑定为另一个按键。对于本例就是:

  • 当展现候选菜单时,名号键(period)绑定为向后换页(Page_Down);
  • 当已有(向后)换页动作时,逗号键(comma)绑定为向前换页(Page_Up)。

逗号键向前换页的条件之所以比名号键严格,是为了「,」仍可在未进行换页的情况下顶字上屏。

经过 key_binder 的处理,用來换頁的逗号、句号键改头换面前、后换页键,从而绕过 punctuator,最终被 selector 当作换页来处理。

最终的代码如下:

 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
schema:
  schema_id: hello
  name: 大家好
  version: "7"

engine:
  processors:
    - key_binder  # 抢在其他 processor 处理之前判定是否换頁用的符号键
    - speller
    - punctuator  # 否则「,。」就会由此上屏
    - selector
    - navigator
    - express_editor
  segmentors:
    - abc_segmentor
    - punct_segmentor
    - fallback_segmentor
  translators:
    - echo_translator
    - punct_translator
    - table_translator

translator:
  dictionary: hello

punctuator:
  import_preset: default

key_binder:
  bindings:             # 每条定义包含条件、接收按键(IBus 规格的键名,可加修饰符,如 「Control+Return」)、发送按键

    - when:   paging    # 仅当已发生向后换页时
      accept: comma     # 将「逗号」键……
      send:   Page_Up   # 关联到「向前换页」;于是 navigator 将收到一发 Page_Up

    - when:   has_menu  # 只要有候选字即满足条件
      accept: period
      send:   Page_Down

修炼之道

与 「 大家好 」这个方案不同。以下一组示例,主要演示如何活用符号键盘,以及罗马字转写式输入。

¹改造键盘

不要以为 「 大家好 」是最最简单的输入方案。码表式输入法,不如键盘式输入法来得简单明快!

用 punctuator 这一套組件,就可实现一款键盘输入法:

 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
# Rime schema
# encoding: utf-8

schema:
  schema_id: numbers
  name: 数字之道
  version: "1"

engine:
  processors:
    - punctuator
    - express_editor
  segmentors:
    - punct_segmentor
  translators:
    - punct_translator

punctuator:
  half_shape: &symtable
    "1" : 
    "2" : 
    "3" : 
    "4" : 
    "5" : 
    "6" : 
    "7" : 
    "8" : 
    "9" : 
    "0" : 
    "s" : 
    "b" : 
    "q" : 
    "w" : 
    "n" : 
    "y" : [ 月, 元, 億 ]
    "r" : 
    "x" : 星期
    "j" : 
    "f" : 
    "z" : [ 之, 整 ]
    "d" : 
    "h" : 
    "." : 
  full_shape: *symtable

对,所谓「键盘输入法」,就是按键选字直接对应的输入方式。

这次,不再写 punctuator/import_preset 这项,而是自订了一套符号表。

哦!原来 punctuator 不单可以用来打出标点符号;还可以重定义空格以及全部 94 个可打印 ASCII 字符(码位 0x200x7e)。

在符号表代码里,用对应的 ASCII 字符表示按键。记得这些按键字符要放在引号里面,YAML 才能夠正确解析喔。

示例代码表演了两种符号的映射方式:一对一及一对多。一对多者,按键后符号不会立即上屏,而是……嘿嘿,自己体验吧 🤣

关于代码里 symtable 的一点解释:

这是 YAML 的一种语法,&symtable 叫做「锚点标签」,给紧随其后的内容起个名字叫 symtable; *symtable 则相当于引用了 symtable 所标记的那段內容,从而避免重复。

Rime 里的符号有「全角」、「半角」两种状态。本方案里暂不作区分,教 half_shapefull_shape 使用同一份符号表。

²大写数字键盘

灵机一动,不如复用「全、半角」模式来区分「大、小写」中文数字!

1
2
3
4
5
6
7
8
9
schema:
  # ...
  version: "2"

switches:
  - name: full_shape
    states: [ 小写, 大寫 ]

# ...

先来定义状态开关:0 能改「 半角 」为「 小写 」,1 能改「 全角 」为「 大寫 」。

这样一改,再打开「 方案选单 」,方案「 数字之道 」底下就会多出个「 小写→大寫」的选项,每选定一次、状态随之反转一次。

接着给  half_shapefull_shape 定义不同的符号表:

 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
punctuator:
  half_shape:
    "1" : 
    "2" : 
    "3" : 
    "4" : 
    "5" : 
    "6" : 
    "7" : 
    "8" : 
    "9" : 
    "0" : 
    "s" : 
    "b" : 
    "q" : 
    "w" : 
    "n" : 
    "y" : [ 月, 元, 億 ]
    "r" : 
    "x" : 星期
    "j" : 
    "f" : 
    "z" : [ 之, 整 ]
    "d" : 
    "h" : 
    "." : 
  full_shape:
    "1" : 
    "2" : 
    "3" : 
    "4" : 
    "5" : 
    "6" : 
    "7" : 
    "8" : 
    "9" : 
    "0" : 
    "s" : 
    "b" : 
    "q" : 
    "w" : 
    "n" : 
    "y" : [ 月, 圓, 億 ]
    "r" : 
    "x" : 星期
    "j" : 
    "f" : 
    "z" : [ 之, 整 ]
    "d" : 
    "h" : 
    "." : 

哈,调出选单切换一下大小写,输出的字全变样!酷。

但是要去选单切换,总不如按下 Shift 就全都有了:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
punctuator:
  half_shape:
    # ... 添加以下這些
    "!" : 
    "@" : 
    "#" : 
    "$" : [ 肆, ¥, "$", "€", "£" ]
    "%" : [ 伍, 百分之 ]
    "^" : 
    "&" : 
    "*" : 
    "(" : 
    ")" : 
    "S" : 
    "B" : 
    "Q" : 
    "Y" : 

于是在「 小写 」状态,只要按 shift + 数字键 即可打出大写数字。

用了几下,发现一处小小的不满意:敲 $ 这个键,可选的符号有一个之多。想要打出欧元、英磅符号只得多敲几下 $ 键使用想要的符号高亮。但是按上、下方向键并没有效果,按符号前面标示的数字序号,更是不仅上屏了错误的符号、还多上屏一个数字。

这反映出两个问题。

① 是 selector 组件缺席使得选字、移动选字光标的动作未得到响应。立即加上:

1
2
3
4
5
6
7
8
# ...

engine:
  processors:
    - punctuator
    - selector        # 加在这里
    - express_editor
  # ...

因为要让 punctuator 来转换数字键,所有 selector 得放在它后头。

② 是无法用数字序号选字。为解决这个冲突,改用闲置的字母键来选字:

1
2
3
4
# ...

menu:
  alternative_select_keys: "acegi"

完工。

³罗马字之道

毕竟,键盘上只有 7 个字符按键、94 个编码字符,对付百十个字还管使。可要输入上千个常用汉字,嫌键盘式输入的编码空间太小,必得采用字符编码。

罗马字,以拉丁字母的特定排列作为汉语音节的转写形式。一个音节代表一组同音字,再由音节拼写组合词、句。

凡此单字(音节)编码自然连用而生词、句的输入法,皆可用  script_translator 组件完成基于音节码切分的智能词句转换。它有个别名 r10n_translator —— r10n 为 romanization 的简写。但不限于「 拼音、注音、双拼」等一族基于语音编码的输入法。形式相似者,如「 速成 」,难以字形为本,亦可应用。

现在来把「 数字之道 」改成 「 拼音→中文数字」的变换。

 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
schema:
  schema_id: numbers
  name: 数字之道
  version: "3"

engine:
  processors:
    - speller
    - punctuator
    - selector
    - express_editor
  segmentors:
    - abc_segmentor
    - punct_segmentor
  translators:
    - punct_translator
    - script_translator

translator:
  dictionary: numbers

punctuator:
  half_shape: &symtable
    "!" : 
    "@" : 
    "#" : 
    "$" : [ 肆, ¥, "$", "€", "£" ]
    "%" : [ 伍, 百分之 ]
    "^" : 
    "&" : 
    "*" : 
    "(" : 
    ")" : 
    "S" : 
    "B" : 
    "Q" : 
    "W" : 
    "N" : 
    "Y" : [ 月, 圓, 億 ]
    "R" : 
    "X" : 星期
    "J" : 
    "F" : 
    "Z" : [ 之, 整 ]
    "D" : 
    "H" : 
    "." : 
  full_shape: *symtable

符号表里,把小写字母、数字键都空出来了。小写字母用来拼音,数字键用来选重。重点是本次用了  script_translator 这组件。与 table_translator 相似,该组件与  translator/dictionary 指名的词典相关联。

编制词典:

 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
# Rime dictionary
# encoding: utf-8

---
name: numbers
version: "1"
sort: by_weight
use_preset_vocabulary: true
...

一	yi
二	er
三	san
四	si
五	wu
六	liu
七	qi
八	ba
九	jiu
〇	ling
零	ling
十	shi
百	bai
千	qian
萬	wan
億	yi
年	nian
月	yue
日	ri
星	xing
期	qi
時	shi
分	fen
秒	miao
元	yuan
角	jiao
之	zhi
整	zheng
第	di
號	hao
點	dian
是	shi

码表里给出了一个「 示例 」规格的小字集。其中包含几组重码字。

要诀 sort: by_weight 意图是不以码表的顺序排列码字,而是比较字频。那字频呢?没写出来。

要诀 use_preset_vocabulary: true 用在输入方案需要支持输入词组、而码表中词组相对匮乏时。编译输入方案期间引入 Rime 预设的「 八股文 」词汇 - 及词频资料!这就是码表中未具体字频的原因。

使用「 八股文 」,要注音码表所用的字形是否与该词汇表一致。八股文的词汇及词频统计都遵照 opencc 繁体字形标准。

如果缺少单字的编码定义,自然也无法导入某些词汇。所以本方案吸有导入这个数字「 小字集 」上的词汇。

⁴用拼写运算定义简码

如今有了一款专门输入数字的拼音输入法。比一比升阳拼音、朙月拼音和地球拼音,还有哪里不一样?

很快我发现敲 xingqiwu 或 xingqiw 都可得到来自「 八股文 」的词组 “星期五”,这很好。可以敲 xqw 怎会不中呢?

原来 script_translator 罗马字中译的方法是,将输入码序列切分为音节表中的拼写形式,再按音节查词典。不信你找本词典瞧瞧,是不是按完整的拼音(注音)编排的。Rime 词典也一样,并没有 xqw 这样的检索码。

现在我要用 Rime 独门绝活「 拼写运算 」 来定义一种 「 音序查字法 」。令 xxing 的简码, q 作数字之道所有音节中起首为 q 者的简码,即略代音节 qiqian

汉语拼音里还有三个双字母的声符, zh、ch、sh 也可以做简码。

添加拼写运算规则:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
schema:
  # ...
  version: "4"

#...

speller:
  algebra:
    - 'abbrev/^([a-z]).+$/$1/'
    - 'abbrev/^([zcs]h).+$/$1/'

如此 Rime 便知,除了码表里那些拼音,还有若干简码也是行得通的拼写形式。再输入 xqw,Rime 将它拆开 x'q'w,再默默对应到音节码 xing'qi'wanxing'qi'wuxing'qian'wan 等等,一翻词典就得到了一个好词「 星期五 」,而其他的组合都说不通。

现在有没有悟到,罗马字转写式输入法与码表式输入法理念上的不同?

哈,做中了。试试看 sss,sss,sssss,sssss

却好像不是我要的 「四是四,十是十,十四是十四,四十是四十」……

好办。如果某些词汇在方案里很重要,「 八股文 」又未收录,那么,请添加到码表:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
---
name: numbers
version: "2"
sort: by_weight
use_preset_vocabulary: true
...

# ...

四是四
十是十
十四是十四
四十是四十

善哉。演示完毕。当然休想就此把 Rime 全盘掌握了。一本《指南书》,若能让读者入门,我只能说「 善哉~ 」

再往后,就只有多读代码,就能见识到各种新颖、有趣的玩法。

最高武艺

⚠️ 警告,最后这部戏,对智力、技术功底的要求不一般。如果读不下去,不要怪我、不要怀疑自己的智商。

即使路过本节也无妨,只是不可忽略了正文「 关于调试 」这一节。(重要哇……)

请检查是否:

  • 已将前两组实例分析透彻
  • 学习完了《 拼写运算 》
  • 知道双拼是什么
  • 预习 Rime 预设输入方案之「 朙月拼音 」

设计一款「 智能 ABC 双拼 」输入方案做练习!

  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
# Rime schema
# encoding: utf-8

schema:
  schema_id: double_pinyin_abc  # 专有的方案标识
  name: 智能ABC双拼
  version: "0.9"
  author:
    - 佛振 <chen.sst@gmail.com>
  description: |
        朙月拼音,兼容智能ABC双拼方案。

switches:
  - name: ascii_mode
    reset: 0
    states: [ 中文, 西文 ]
  - name: full_shape
    states: [ 半角, 全角 ]
  - name: simplification
    states: [ 漢字, 汉字 ]

engine:
  processors:
    - ascii_composer
    - recognizer
    - key_binder
    - speller
    - punctuator
    - selector
    - navigator
    - express_editor
  segmentors:
    - ascii_segmentor
    - matcher
    - abc_segmentor
    - punct_segmentor
    - fallback_segmentor
  translators:
    - echo_translator
    - punct_translator
    - script_translator
    - reverse_lookup_translator
  filters:
    - simplifier
    - uniquifier

speller:
  alphabet: zyxwvutsrqponmlkjihgfedcba  # 呃,倒背字母表完全是个人喜好
  delimiter: " '"  # 隔音符号用「'」;第一位的空白用來自动插入到音节边界处
  algebra:  # 拼写运算规则,这个就是实现双拼方案的重点。写法有很多种,当然也可以把四百多个音节码一条条都列举
    - erase/^xx$/             # 码表中有几個拼音不明的字,编码成xx了,消灭它
    - derive/^([jqxy])u$/$1v/
    - xform/^zh/A/            # 替换声母键,用大写以防与原有的字母混淆
    - xform/^ch/E/
    - xform/^sh/V/
    - xform/^([aoe].*)$/O$1/  # 添上固定的零声母o,先标记为大写O
    - xform/ei$/Q/            # 替换韵母键
    - xform/ian$/W/           # ※2
    - xform/er$|iu$/R/        # 对应两种韵母的;音节 er 现在变为 OR 了
    - xform/[iu]ang$/T/       # ※1
    - xform/ing$/Y/
    - xform/uo$/O/
    - xform/uan$/P/           # ※3
    - xform/i?ong$/S/
    - xform/[iu]a$/D/
    - xform/en$/F/
    - xform/eng$/G/
    - xform/ang$/H/           # 检查一下在此之前是否已转换过了帶介音的ang;好,※1处有了
    - xform/an$/J/            # 如果※2、※3还没有出现在上文中,应该把他们提到本行之前
    - xform/iao$/Z/           # 对——像这样让iao提前出场
    - xform/ao$/K/
    - xform/in$|uai$/C/       # 让uai提前出场
    - xform/ai$/L/
    - xform/ie$/X/
    - xform/ou$/B/
    - xform/un$/N/
    - xform/[uv]e$|ui$/M/
    - xlit/QWERTYOPASDFGHJKLZXCVBNM/qwertyopasdfghjklzxcvbnm/  # 最后把双拼码全部变小写

translator:
  dictionary: luna_pinyin     # 与【朙月拼音】共用词典
  prism: double_pinyin_abc    # prism 要以本输入方案的名称来命名,以免把朙月拼音的拼写映射表覆盖掉
  preedit_format:             # 这段代码用来将输入的双拼码反转为全拼显示;若想直接显示双拼码可以把这段注释掉
    - xform/o(\w)/0$1/        # 零声母先改为0,以方便后面转换
    - xform/(\w)q/$1ei/       # 双拼第二码转换为韵母
    - xform/(\w)n/$1un/       # 提前转换双拼码 n 和 g,因为转换后的拼音里就快要出现这两个字母了,那时将难以分辨出双拼码
    - xform/(\w)g/$1eng/      # 当然也可以采取事先将双拼码变为大写的办法来与转换过的拼音做区分,可谁让我是高手呢
    - xform/(\w)w/$1ian/
    - xform/([dtnljqx])r/$1iu/  # 对应多种总线的双拼码,按搭配的声母做区分(最好别用排除式如 [^o]r  容易出状况)
    - xform/0r/0er/             # 另一种情况,注音先不消除0,以防后面把e当作声母转换为ch
    - xform/([nljqx])t/$1iang/
    - xform/(\w)t/$1uang/       # 上一行已经把对应到 iang 的双拼码 t 消减,于是这里不用再列举相配的声母
    - xform/(\w)y/$1ing/
    - xform/([dtnlgkhaevrzcs])o/$1uo/
    - xform/(\w)p/$1uan/
    - xform/([jqx])s/$1iong/
    - xform/(\w)s/$1ong/
    - xform/([gkhaevrzcs])d/$1ua/
    - xform/(\w)d/$1ia/
    - xform/(\w)f/$1en/
    - xform/(\w)h/$1ang/
    - xform/(\w)j/$1an/
    - xform/(\w)k/$1ao/       # 默默检查:双拼码 o 已经转换过了
    - xform/(\w)l/$1ai/
    - xform/(\w)z/$1iao/
    - xform/(\w)x/$1ie/
    - xform/(\w)b/$1ou/
    - xform/([nl])m/$1ve/
    - xform/([jqxy])m/$1ue/
    - xform/(\w)m/$1ui/
    - "xform/(^|[ '])a/$1zh/"  # 复原声母,音节开始处的双拼字母 a 改写为 zh;其他位置的才真正是 a
    - "xform/(^|[ '])e/$1ch/"
    - "xform/(^|[ '])v/$1sh/"
    - xform/0(\w)/$1/          # 好了,現在可以把零声母拿掉啦
    - xform/([nljqxy])v/$1ü/   # 这要就是汉语拼音 :-)

reverse_lookup:
  dictionary: cangjie5
  prefix: "`"
  tips: 〔仓颉〕
  preedit_format:
    - "xlit|abcdefghijklmnopqrstuvwxyz|日月金木水火土竹戈十大中一弓人心手口尸廿山女田難卜符|"
  comment_format:
    - xform/([nl])v/$1ü/

punctuator:
  import_preset: default

key_binder:
  import_preset: default

recognizer:
  import_preset: default
  patterns:
    reverse_lookup: "`[a-z]*$"

完毕。

这是一道大题。通过改造拼写法而创作出新的输入方案。

标准库

如果需要制作完全属于自己的输入方案,少不了要了解 Rime 的标准库。些时,可以参阅 《Rime方案制作详解》。更多新意,就在你的笔下!

关于调试

如此复杂的输入方案,很可能需要反复调试方可达到想要的结果。

请于试验时及时查看日志中是否包含错误信息。日志文件位于:

  • 【中州韵】 /tmp/rime.ibus.*
  • 【小狼毫】 %TEMP%\rime.weasel.*
  • 【鼠须管】 $TMPDIR/rime.squirrel.*
  • 各发行版的早期版本 用戶資料夾/rime.log

按照日志级别分为 INFO/信息、WARNING/警告、ERROR/错误。后两类应重点关注,如果新方案部署后不可用或输出与设计不一致,原因可能在此。

没有任何错误信息,就是不好使,有可能是码表本身的问题,比如把码表中文字和编码两列弄颠倒了 – Rime 等你输入由汉字组成的编码,然而键盘没有可能做到这一点(否则也不再需要输入法了)。

后续有计划为输入方案创作者开发名为 「拼写运算调试器」 的工具,能够较直观都看到第一步拼写运算的结果。有助于定义双拼这样大量使用拼写运算的方案。

方案制作详解

更多参阅 雪齐的文档

开始之前

# Rime schema
# encoding: utf-8

描述档

¹ name:方案的显示名称(即出现于方案选单中的方案名称,通常为中文)

² schema_id:方案内部名,在代码中引用此方案时以此名为正,通常由英文、数字、下划线组成。

³ author :发明人、撰写者。如果你对方案做出了修改,请保留原作者名,并将自己的名字加在后面。

description:简要描述方案历史、码表来源、该方案规则等。

dependencies:如果本方案信赖于基字方案(通常来说会信赖其它方案做为反查,抑或是两种或多种方案混用时)。

version:版本号,在发布新版前请确保已升级版本号。

schema:
  name: "仓颉检字法"
  schema_id: cangjie6
  author:
    - "发明人 朱邦復先生、沈紅蓮女士"
  dependencies:
    - luna_pinyin
    - jyutping
    - zyenpheng
  description: |
    第六代仓颉输入法
    码表由雪齋、惜緣和crazy4u整理
  version: 0.19

开关

通常包含以下数个,但并不限于此,自定义滤镜皆可设置开关调控

¹ ascii_mode:是中英文转换开关,默认 0 为中文,1 为英文。

² full_shape:是全角符号 / 半角符号开关。0 为半角,1 为全角。注音,开启全角时英文字母亦为全角。

³ extended_charset:是字符集开关。0 为 CJK 基本字符集,1 为 CJK 全字符集。(仅 table_translator 可用)

ascii_punct:是中西文标点转换开关,0 为中文标点,1 为英文标点。

simplification :是转化字开关。一般情况下与上同,0 为不开启转化,1 为开启转化。

所有开关名称可自定义,可用快捷键切换。该名称可用于 key_binder/bindings 中的 toggle: 后。

- name: simplification
  states: ["漢字", "汉字"]
  reset: 0

亦可使用多选开关,同样支持快捷键:options 名称用于 key_binder/bindings 时,使用 set_option:unset_option: 开启或关闭某一个。

- options: [ zh_trad, zh_cn, zh_mars ]
  states:
    - 字型 → 漢字
    - 字型 → 汉字
    - 字型 → 䕼茡
  reset: 0

其中:

  • name / options 名:需与 simplifieroption_name 相同;
  • states:可不写,如不写则此开关存在但不可见,可由快捷键操作;
  • reset:设定默认状态(reset 可不写,此时切换窗口时不会重置到默认状态)。
switches:
  - name: ascii_mode
    reset: 0
    states: ["中文", "西文"]
  - name: full_shape
    states: ["半角", "全角"]
  - name: extended_charset
    states: ["通用", "增廣"]
  - name: simplification
    states: ["漢字", "汉字"]
  - name: ascii_punct
    states: ["句讀", "符號"]

引擎

以下加粗项为可细配者,斜体为不常用者。

引擎分四组。

processors

这批组件处理各类按键消息。

¹ ascii_composer 处理西文模式及中西文切。

² recognizer 与 matcher 搭配,处理符合特定规则的输入码,如网址、反查等 tags

³ key_binder 在特定条件下将按键绑定到其他按键,如重定义逗号、句号为候选翻页、开关快捷键等。

speller 拼写处理器,接受字符按键,编辑输入。

punctuator 句读处理器,将单个字符按键直接映射为标点符号或文字。

selector 选字处理器,处理数字选字键(可以换成别的)、上、下选定位、换页。

navigator 处理输入栏内的光标移动。

express_editor 编辑器,处理空格、回车上屏、回退键。

fluid_editor 句式编辑器,用于以空格断词、回车上屏的「 注音、语句流 」等输入方案,替换 express_editor

¹⁰ chord_composer 和弦作曲家或曰并击处理器,用于「 宫保拼音 」等多键并击的输入方案。

¹¹ lua_processor 使用 lua 自定义按键,后接 @ + lua 函数名lua 函数名 即用户文件夹内 rime.lua 中的函数名,参数为 (key, env)

:: 当然,现在的版本已经支持 *.lua 脚本自动执行了。

segmentors

这批组件识别不同内容类型,将输入码分段并加上 tag

¹ ascii_segmentor 标识西文段落(比如在西文模式下)字母直接上屏。

² matcher 配合 recognizer 标识符合特定规则的段落,如网址、反查等,加上选定 tag

³ abc_segmentor 标识常规的文字段落,加上 abc 这个 tag

punct_segmentor 标识句读段落(键入标点符号用),加上 punct 这个 tag

fallback_segmentor 标识其他示标识段落。

affix_segmentor 用户自定义 tag。此项可加载多个实例,后接 @ + tag 名。

lua_segmentor 使用 lua 自定义切分,后接 @ + tag 函数名。

translators

这批组件翻译特定类型的编码段为一组候选文字。

¹ echo_translator 没有其它候选字时,回显输入码(输入码可以 Shift + Enter 上屏)。

² punct_translator 配合 punct_segmentor 转换标点符号。

³ table_translator 码表翻译器,用于仓颉、五笔等基于码表的输入方案。此项可加载多个实例,后接 @ + 翻译器名 (如 cangjiewubi)等。

script_translator 脚本翻译器,用于拼音、粤拼等基于音节表的输入方案。此项可加载多个实例,后接 @ + 翻译器名 (如 pinyinjyutping)等。

reverse_lookup_translator 反查翻译器,用另一种编码方案查码。

history_translator 产生 commit 历史候选。其中:

  • tag 同 Translator 说明;
  • initial_quality 同 Translator 说明;
  • size 设定候选记录量,预设为 0 等同(commit_record 最大储存量为 20);
  • input 触发此翻译器的字串。

lua_translator 使用 lua 自定义输入,例如动态输入当前日期、时间,后接 @ + lua 函数名。其中:

  • lua 函数名即用户文件夹内 rime.lua 中函数名,参数为 (input, seg, env)
  • 可以 env.engine.context:get_option("option_name") 方式绑定到 switch 开关 / key_binder 快捷键。

filters

这批组件过滤翻译的结果,自定义滤镜皆可使用开关调控。

¹ uniquifier 过滤重复的候选字,有可能来自 simplifier

² cjk_minifier 字符集过滤(仅用于 script_translator,使之支援 extended_charset 开关)。

³ single_char_filter 单字过滤器,如加载此组件,则屏蔽词典中的词组(仅 table_translator 有效)。

simplifier 用字转换。

reverse_lookup_filter 反查滤镜,以更灵活的方式反查,Rime1.0 后替代 reverse_lookup_translator。此项可加载多个实例,后接 @ +滤镜名〔如:pinyin_lookupjyutping_lookup 等〕。

lua_filter 使用 lua 自定义过滤,例如过滤字符集、高速排序,后接 @ + lua 函数名。其中:

  • lua 函数名即用户文件夹内 rime.lua 中函数名,参数为 (input, seg, env)
  • 可以 env.engine.context:get_option("option_name") 方式绑定到 switch 开关 / key_binder 快捷键。

> cangjie6.schema.yaml

engine:
  processors:
    - ascii_composer
    - recognizer
    - key_binder
    - speller
    - punctuator
    - selector
    - navigator
    - express_editor
  segmentors:
    - ascii_segmentor
    - matcher
    - affix_segmentor@pinyin
    - affix_segmentor@jyutping
    - affix_segmentor@pinyin_lookup
    - affix_segmentor@jyutping_lookup
    - affix_segmentor@reverse_lookup
    - abc_segmentor
    - punct_segmentor
    - fallback_segmentor
  translators:
    - punct_translator
    - table_translator
    - script_translator@pinyin
    - script_translator@jyutping
    - script_translator@pinyin_lookup
    - script_translator@jyutping_lookup
    - lua_translator@get_date
  filters:
    - simplifier@zh_simp
    - uniquifier
    - cjk_minifier
    - reverse_lookup_filter@middle_chinese
    - reverse_lookup_filter@pinyin_reverse_lookup
    - reverse_lookup_filter@jyutping_reverse_lookup
    - lua_filter@single_char_first

细项配置

comment_formatpreedit_formatspeller/algebra 所用之正则表达式,请参阅 「Perl 正则表达式」

引擎中所举之加粗者堍可在正文详细描述,格式为:

name:
  branches: configurations

name:
  branches:
    - configurations

speller

¹ alphabet: 定义本方案定义本方案输入键。

² initials: 定义仅作始码之键。

³ finals: 定义仅作末码之键。

delimiter: 上屏时的音节间分音符。

algebra: 拼写运算规则,由之算出的拼写汇入 prism 中。

max_code_length: 形码最大码长,超过则顶字上屏(number)。

auto_select: 自动上屏( truefalse)。

auto_select_pattern: 自动上屏规则,以正则表达式描述,当输入串可以被匹配时自动顶字上屏。

use_space: 以空格作输入码(truefalse)。

speller 的演算包含:

xform  -- 改写〔不保留原形〕
derive -- 衍生〔保留原形〕
abbrev -- 简拼〔出字优先级较上两组更低〕
fuzz   -- 略拼〔此种简拼仅组词,不出单字〕
xlit   -- 变换〔适合大量一对一变换〕
erase  -- 刪除

> luna_pinyin.schema.yaml

speller:
  alphabet: zyxwvutsrqponmlkjihgfedcba
  delimiter: " '"
  algebra:
    - erase/^xx$/
    - abbrev/^([a-z]).+$/$1/
    - abbrev/^([zcs]h).+$/$1/
    - derive/^([nl])ve$/$1ue/
    - derive/^([jqxy])u/$1v/
    - derive/un$/uen/
    - derive/ui$/uei/
    - derive/iu$/iou/
    - derive/([aeiou])ng$/$1gn/
    - derive/([dtngkhrzcs])o(u|ng)$/$1o/
    - derive/ong$/on/
    - derive/ao$/oa/
    - derive/([iu])a(o|ng?)$/a$1$2/

segmentor

segmentor 配合 recognizer s 标记出 tag,这里会用到 affix_segmentorabc_segmentor

tag 用在 translatorreverse_lookup_filtersimplifier 中用以标定各自作用范围。如果不需要用到 extra_tags 则不需要单独配置 segmentor。其中:

  1. tag: 设定其 tag
  2. prefix: 设定其前缀标识,可不填,不填则无前缀;
  3. suffix: 设定其尾缀标识,可不填,不填则无尾缀;
  4. tips: 设定其输入前提示符,可不填,不填则无提示符;
  5. closing_tips: 设定其结束输入提示符,可不填,不填则无提示符;
  6. extra_tags: 为此 segmentor 所标记的段落插上其它 tag

affix_segmentortranslator 重名时,两者可并在一直配置,此处1-5 条对应下面 21-25 条。abc_segmentor 仅可设 extra_tags

> cangjie6.schema.yaml

reverse_lookup:
  tag: reverse_lookup
  prefix: "`"
  suffix: ";"
  tips: "【反查】"
  closing_tips: "【蒼頡】"
  extra_tags:
    - pinyin_lookup
    - jyutping_lookup

translator

每个方案都有一个主 translator,在引擎列表不以 @ + 翻译器名定义,在细项配置时直接以 translator: 命名。以下加粗项为可以主 translator 中定义之项,其它可在副〔以 @ + 翻译器名命名〕 translator 中定义。

¹ enable_charset_filter: 是否开启字符集过滤〔仅 table_translator 有效。启用 cjk_minifier 后可适用于 script_translator

² enable_encoder: 是否开启自动造词〔仅 table_translator 有效〕

³ encode_commit_history: 是否对已上屛词自动成词〔仅 table_translator 有效〕

max_phrase_length: 最大自动成词词长〔仅 table_translator 有效〕

enable_completion: 提前显示尚未输入完整码的字〔仅 table_translator 有效〕

enable_correction: 启用自动纠错〔仅 script_translator 有效〕

sentence_over_completion: 在无全码对应字而仅有逐键提示时也开启智能组句〔仅 table_translator 有效〕

strict_spelling: 配合 speller 中的 fuzz 规则,仅以略拼码组词〔仅 table_translator 有效〕

disable_user_dict_for_patterns: 禁止某些编码录入用户词典

¹⁰ enable_sentence: 是否开启自动造句

¹¹ enable_user_dict: 是否开启用户词典〔 用户词典记录动态字词频、用户词〕,以上选填 truefalse

¹². dictionary: 翻译器将调取此字典文件

¹³ prism: 设定由此主翻译器的 speller 生成的棱鏡文件名,或此副编译器调用的棱鏡名

¹⁴ user_dict: 设定用戶詞典名

¹⁵ db_class: 设定用戶词典类型,可设 tabledb 〔文本〕或 userdb 〔二进制〕

¹⁶ preedit_format: 上屛码自定义

¹⁷ comment_format: 提示码自定义

¹⁸ spelling_hints: 设定多少字以內候选标注完整带拼音〔仅 script_translator 有效〕

¹⁹ always_show_comments:  始终显示提示码〔仅 script_translator 有效〕

²⁰ initial_quality: 设定此翻译器出字优先级

²¹ tag: 设定此翻译器针对的 tag。可不填,不填则仅针对 abc

²² prefix: 设定此翻译器的前缀标识,可不填,不填则无前缀

²³ suffix: 设定此翻译器的尾缀标识,可不填,不填则无尾缀

²⁴ tips: 设定此翻译器的输入前提示符,可不填,否则则无提示符

²⁵ closing_tips: 设定此翻译器的结束输入提示符,可不填,不填则无提示符

²⁶ contextual_suggestions: 是否使用语言模型优化输出结果〔需配合 grammar 使用〕

²⁷ max_homophones: 最大同音簇长度〔需配合 grammar 使用〕

²⁸ max_homographs: 最大同形簇长度〔需配合 grammar 使用〕

> cangjie6.schema.yaml 仓颉主翻译器

translator:
  dictionary: cangjie6
  enable_charset_filter: true
  enable_sentence: true
  enable_encoder: true
  encode_commit_history: true
  max_phrase_length: 5
  preedit_format:
    - xform/^([a-z ])$/$1|\U$1\E/
    - xform/(?<=[a-z])\s(?=[a-z])//
    - "xlit|ABCDEFGHIJKLMNOPQRSTUVWXYZ|日月金木水火土竹戈十大中一弓人心手口尸廿山女田止卜片|"
  comment_format:
    - "xlit|abcdefghijklmnopqrstuvwxyz~|日月金木水火土竹戈十大中一弓人心手口尸廿山女田止卜片・|"
  disable_user_dict_for_patterns:
    - "^z.$"
  initial_quality: 0.75

> cangjie6.schema.yaml 拼音副翻译器

pinyin:
  tag: pinyin
  dictionary: luna_pinyin
  enable_charset_filter: true
  prefix: 'P' # 需配合recognizer
  suffix: ';' # 需配合recognizer
  preedit_format:
    - "xform/([nl])v/$1ü/"
    - "xform/([nl])ue/$1üe/"
    - "xform/([jqxy])v/$1u/"
  tips: "【漢拼】"
  closing_tips: "【蒼頡】"

> pinyin_simp.schema.yaml 拼音・简化字主翻译器

translator:
  dictionary: luna_pinyin
  prism: luna_pinyin_simp
  preedit_format:
    - xform/([nl])v/$1ü/
    - xform/([nl])ue/$1üe/
    - xform/([jqxy])v/$1u/

> luna_pinyin.schema.yaml 朙月拼音用戶短语

custom_phrase: #這是一個table_translator
  dictionary: ""
  user_dict: custom_phrase
  db_class: tabledb
  enable_sentence: false
  enable_completion: false
  initial_quality: 1

reverse_lookup_filter

此滤镜需挂在 translator 上,不影响该 translator 工作。

¹ tags: 设定其作用范围。

² overwrite_comment: 是否覆盖其他提示。

³ dictionary: 反查所得提示码之码表。

comment_format: 自定义提示码格式。

apply_comment:

> cangjie6.schema.yaml

pinyin_reverse_lookup:    # 该反查滤镜名
  tags: [ pinyin_lookup ] # 挂在这个 tag 所对应的翻译器上
  overwrite_comment: true
  dictionary: cangjie6    # 反查所得为仓颉码
  comment_format:
    - "xform/$/〕/"
    - "xform/^/〔/"
    - "xlit|abcdefghijklmnopqrstuvwxyz |日月金木水火土竹戈十大中一弓人心手口尸廿山女田止卜片、|"

simplifier

¹ option_name: 对应 switches 中设定的切换项名,即 key_binder/binding 中所用名。

² opencc_config: 用字转换配置文件。位于 rime_dir/opencc/,自带配置文件包含:

  1. 繁转简〔默认〕:t2s.json
  2. 繁转台湾:t2tw.json
  3. 繁转香港:t2hk.json
  4. 简转繁:s2t.json

³ tags: 设定转换范围。

tips: 设定是否显示转换前的字,可填 none(或不填)、char(仅对单字有效)、all

comment_format: 自定义提示码格式。

allow_erase_comment: 是否允许返回空提示码(默认 false)。

show_in_comment: 设定是否将转换结果显示在备注中。

excluded_types: 取消选定范围(一般为 reverse_lookup_translator )转化用字。

修改自 luna_pinyin_kunki.schema

zh_tw:
  option_name: zh_tw
  opencc_config: t2tw.json
  tags: [ abc ] # abc 对应 abc_segmentor
  tips: none
  allow_erase_comment: true
  comment_format:
    - xform/.*//

chord_composer

并击把键盘分两半,相当于两块键盘。两边同时击键,系统默认在其中一半上按的键等于另一半,由此得出上屏码。

¹ alphabet: 字母表,包含用于并击的按键。击键虽有先后,形成并击时,一律以字母表顺序排列。

² algebra: 拼写运算规则,将一组并击编码转换为拼音音节。

³ output_format: 并击完成后套用的式样,追加隔音符号。

prompt_format: 并击过程中套用的式样,加方括号弧。

> combo_pinyin.schema.yaml

chord_composer:
  # 字母表,包含用于并击的按键
  # 击键虽有先后,形成并击时,一律以字母表顺序排列
  alphabet: "swxdecfrvgtbnjum ki,lo."
  # 拼写运算规则,将一级并击编码转换为拼音音节
  algebra:
    # 先将物理按键字符对应到宫保拼音键位中的拼音字母
    - 'xlit|swxdecfrvgtbnjum ki,lo.|sczhlfgdbktpRiuVaNIUeoE|'
    # 以下根据宫保拼音的键位分别变换声母、韵母部分
    # 组合声母
    - xform/^zf/zh/
    - xform/^cl/ch/
    - xform/^fb/m/
    - xform/^ld/n/
    - xform/^hg/r/
    ……
    # 声母独用时补足隐含的韵母
    - xform/^([bpf])$/$1u/
    - xform/^([mdtnlgkh])$/$1e/
    - xform/^([mdtnlgkh])$/$1e/
    - xform/^([zcsr]h?)$/$1i/
  # 并击完成后套用的式样,追加隔音符号
  output_format:
    - "xform/^([a-z]+)$/$1'/"
  # 并击过程中套用的式样,加方括弧
  prompt_format:
    - "xform/^(.*)$/[$1]/"

lua

可以参考 Extending RIME with Lua scripts 以寻求更多灵感。

  1. lua_translator
  2. lua_filter
  3. lua_processor
  4. lua_segmentor

> rime.lua

function get_date(input, seg, env)
  --- 以 show_date 为开关名或 key_binder 中 toggle 的对象
  on = env.engine.context:get_option("show_date")
  if (on and input == "date") then
    --- Candidate(type, start, end, text, comment)
    yield(Candidate("date", seg.start, seg._end, os.date("%Y年%m月%d日"), " 日期"))
  end
end
---
function single_char_first(input, env)
  --- 以 single_char 为开关名或 key_binder 中 toggle 的对象
  on = env.engine.context:get_option("single_char")
  local cache = {}
  for cand in input:iter() do
    if (not on or utf8.len(cand.text) == 1) then
      yield(cand)
    else
      table.insert(cache, cand)
    end
  end
  for i, cand in ipairs(cache) do
    yield(cand)
  end
end

其它

包括 recognizer、key_binder、punctuator。标点、快捷键、二三选重、特殊字符等均于此设置。

¹ import_preset: 由外部统一文件导入。

² grammar: 下设:

  • language: 取值 zh-han[ts]-t-essay-bg[wc] ;
  • collocation_max_length: 最大搭配长度(整句输入可忽略此项);
  • collocation_min_length: 最小搭配长度(整句输入可忽略此项)。

³ recognizer: 下设 patterns: 配合 segmentorprefixsuffix 完成段落划分、tag 分配。 前字段可以为以 affix_segmentor@someTag 定义的 Tag 名,或者 punct、reverse_lookup 两个内设的字段。其它字段不调用输入法引擎,输入即输出(如 url 等字段)。

key_binder: 下设 bindings: 设置功能性快捷键。

每一条 binding 包含: when 作用范围、accept 实际所按之键,以及期望的操作。

操作可为以下任意一个:send 输出按键、toggle 切换开关、send_sequence 输出一串按键、set_option 开某多选开关、unset_option 开某种多选开关、select 选候选字。

  • toggle 可用字段包含各开关名;
  • set_optionunset_option 可用字段包含多选开关名;
  • when 可用字段包含:
- paging     翻页用
- has_menu   操作候选项用
- composing  操作输入码用
- always     全域
  • acceptsend 可用字段除 A-Za-z0-9 外,还包含以下键盘上实际有的键:
BackSpace	    退格
Tab	            水平定位符(制表符)
Linefeed	    换行
Clear	        清除
Return	        回車
Pause	        暫停
Sys_Req	        印屏
Escape	        退出
Delete	        刪除
Home	        原位
Left	        左箭头
Up	            上箭头
Right	        右箭头
Down	        下箭头
Prior、Page_Up	上翻
Next、Page_Down	下翻
End	            末位
Begin	        始位
Shift_L	左Shift
Shift_R	右Shift
Control_L	    左Ctrl
Control_R	    右Ctrl
Meta_L	        左Meta
Meta_R	        右Meta
Alt_L	        左Alt
Alt_R	        右Alt
Super_L	        左Super
Super_R	        右Super
Hyper_L	        左Hyper
Hyper_R	        右Hyper
Caps_Lock	    大写锁
Shift_Lock	    上档锁
Scroll_Lock	    滚动锁
Num_Lock	    小键盘锁
Select	        选定
Print	        打印
Execute	        执行
Insert	        插入
Undo	        还原
Redo	        重做
Menu	        菜单
Find	        查寻
Cancel	        取消
Help	        帮助
Break	        中断
space
exclam	     !
quotedbl	 "
numbersign	 #
dollar	     $
percent	     %
ampersand	 &
apostrophe	 '
parenleft	 (
parenright	 )
asterisk	 *
plus	     +
comma	     ,
minus	     -
period	     .
slash	     /
colon	     :
semicolon	 ;
less	     <
equal	     =
greater	     >
question	 ?
at	         @
bracketleft	 [
backslash	
bracketright ]
asciicircum	 ^
underscore	 _
grave	     `
braceleft	 {
bar	         |
braceright	 }
asciitilde	 ~


KP_Space	            小键板空格
KP_Tab	                小键板水平定位符
KP_Enter	            小键板回车
KP_Delete	            小键板刪除
KP_Home	                小键板原位
KP_Left	                小键板左箭头
KP_Up	                小键板上箭头
KP_Right	            小键板右箭头
KP_Down	                小键板下箭头
KP_Prior、KP_Page_Up	小键板上翻
KP_Next、KP_Page_Down	小键板下翻
KP_End	                小键板末位
KP_Begin	            小键板始位
KP_Insert	            小键板插入
KP_Equal	            小键板等于
KP_Multiply	            小键板乘号
KP_Add	                小键板加号
KP_Subtract	            小键板減号
KP_Divide	            小键板除号
KP_Decimal	            小键板小数点
KP_0	                小键板0
KP_1	                小键板1
KP_2	                小键板2
KP_3	                小键板3
KP_4	                小键板4
KP_5	                小键板5
KP_6	                小键板6
KP_7	                小键板7
KP_8	                小键板8
KP_9	                小鍵板9

editor 用以定制操作键(不支持 import_preset:),键盘键名同 key_binder/bindings 中的 acceptsend,效果定义如下:

confirm	            上屏候选项
commit_comment	    上屏候选项備注
commit_raw_input	上屏原始输入
commit_script_text	上屏变换后输入
commit_composition	语句流单字上屏
revert	            撤消上次输入
back	            按字符回退
back_syllable	    按音节回退
delete_candidate	刪除候选项
delete	            向后刪除
cancel	            取消输入
noop	            空

punctuator: 下设 full_shape:half_shape: 分别控制全角模式下的符号选半角模式下的符号,另有 use_space: 空格顶字(truefalse)。

每条标点项可加 commit 直接上屏选 pair 交替上屏两种模式,默认为选单模式。

> 修改自 cangjie6.schema.yaml


key_binder:
  import_preset: default
  bindings:
    - {accept: semicolon, send: 2, when: has_menu}  # 分号选第二重码
    - {accept: apostrophe, send: 3, when: has_menu} # 引号选第三重码
    - {accept: "Control+1", select: .next, when: always}
    - {accept: "Control+2", toggle: full_shape, when: always}
    - {accept: "Control+3", toggle: simplification, when: always}
    - {accept: "Control+4", toggle: extended_charset, when: always}
editor:
  bindings:
    Return: commit_comment
punctuator:
  import_preset: symbols
  half_shape:
    "'": {pair: ["「", "」"]} # 第一次按是「,第二次是」
    "(": ["〔", "["]         # 弹出选单
    .: {commit: "。"}         # 无选单,直接上屏。优先级最高
recognizer:
  import_preset: default
  patterns:
    email: "^[a-z][-_.0-9a-z]*@.*$"
    url: "^(www[.]|https?:|ftp:|mailto:).*$"
    reverse_lookup: "`[a-z]*;?$"
    pinyin_lookup: "`P[a-z]*;?$"
    jyutping_lookup: "`J[a-z]*;?$"
    pinyin: "(?<!`)P[a-z']*;?$"
    jyutping: "(?<!`)J[a-z']*;?$"
    punct: "/[a-z]*$" # 配合 symbols.yaml 中的特殊字符输入

⁷ 外观

Rime 还为每个方案提供选单选一定的外面定制能力。

通常情况下 menudefault.yaml 中定义(或用户修改档 default.custom.yaml),stylesquirrel.yamlweasel.yaml (或用户修改档 squirrel.custom.yamlweasel.custom.yaml)。


menu:
  alternative_select_labels: [ ①, ②, ③, ④, ⑤, ⑥, ⑦, ⑧, ⑨ ]  # 修改候选标签
  alternative_select_keys: ASDFGHJKL  # 如编码字符占用数字键则需另设选字键
  page_size: 5                        # 选单每页显示个数
style:
  font_face: "HanaMinA, HanaMinB"     # 字体〔小狼毫得且仅得设一个字体;鼠须管得设多个字体,后面的字体自动补前面字体中不含的字〕
  font_point: 15       # 字号
  label_format: '%s'   # 候选标签格式
  horizontal: false    # 橫/直排
  line_spacing: 1      # 行距
  inline_preedit: true # 输入码內嵌

词典详解

# Rime dict
# encoding: utf-8
〔你还可以在这注释字典来源、变动记录等〕

描述档

¹ name: 内部字典名,也即 schma 所引用的字典名,确保与文件名相一致。

² version: 如果发布,请确保每次发动升级版本号。

name: "cangjie6.extended"
version: "0.1"

配置

¹ sort: 字典 初始 排序,可选 originalby_weight

² use_preset_vocabulary: 是否引入「 八股文 」(含字词频、词库)。

³ vocabulary: 引入其他词库(含字词频、词库),此时 use_preset_vocabulary 不可设定为 true

max_phrase_length: 配合 use_preset_vocabulary: ,设定导入词条最大词长。

min_phrase_weight: 配合 use_preset_vocabulary: ,设定导入词条最小词频。

columns: 定义码表以 Tab 分隔出的各列,可设 text(文本)、code(码)、weight(权重)、stem(造词码)。

import_tables: 加载其它外部码表。

encoder: 形码造词规则。

  • exclude_patterns:
  • rules: 可用 length_equal:length_in_range: 定义。大写字母表示字序,小写字母表示其所跟随的大写字母所以表的字中的编码序;
  • tail_anchor: 造词码包含结构分隔符(仅用于仓颉);
  • exclude_patterns 取消某编码的造词资格。

> cangjie6.extended.dict.yaml

sort: by_weight
use_preset_vocabulary: false
import_tables:
  - cangjie6 # 单字码表由 cangjie6.dict.yaml 导入
columns:     # 此字典为纯词典,无单字编码,仅有字和词频
  - text     # 字/词
  - weight   # 字/词频
encoder:
  exclude_patterns:
    - '^z.*$'
  rules:
    - length_equal: 2         # 对于二字詞
      formula: "AaAzBaBbBz"   # 取第一字首尾码、第二字首次尾码
    - length_equal: 3         # 对于三字詞
      formula: "AaAzBaYzZz"   # 取第一字首尾码、第二字首尾码、第三字尾码
    - length_in_range: [4, 5] # 对于四至五字詞
      formula: "AaBzCaYzZz"   # 取第一字首码,第二字尾码、第三字首码、倒数第二字尾码、最后一字尾码
  tail_anchor: "'"

码表

Tab 分隔各列,各列依 columns: 定义排列。

> cangjie6.dict.yaml

columns:
  - text   # 第一列字/词
  - code   # 第二列码
  - weight # 第三列字/词频
  - stem   # 第四列造词码

> cangjie6.dict.yaml

個	owjr	246268	ow'jr
看	hqbu	245668
中	l	243881
呢	rsp	242970
來	doo	235101
嗎	rsqf	221092
爲	bhnf	211340
會	owfa	209844
她	vpd	204725
與	xyc	203975
給	vfor	193007
等	hgdi	183340
這	yymr	181787
用	bq	168934	b'q

词典扩展包

概述

librime 1.6.0 增加了一种扩展词典内容的机制——词典扩展包。可用於为固定音节表的输入方案添加词汇。

固态词典包含 *.table.bin*.prism.bin 两个文件。 前者用於存储来自词典源文件*.dict.yaml 的数据,后者综合了从词典源文件中提取的音节表和输入方案定义的拼写规则。

扩充固态词典内容,旧有在词典文件的 YAML 配置中使用 import_tables 从其他词典源文件导入码表的方法。 此法相当於将其他源文件中的码表内容追加到待编译的词典文件中,再将合併的码表编译成二进制词典文件。

词典扩展包可以达到相似的效果。其实现方式有所不同。 编译过程中,将额外的词典源文件 *.dict.yaml 生成对应的 *.table.bin,其音节表与主码表的音节表保持一致。 使用输入方案时,按照 translator/packs 配置列表中的包名加载额外的 *.table.bin 文件,多表并用,从而一併查得扩充的词汇。

示例

我有一例,请诸位静观。

# 在 Linux 环境做出 librime 及命令行工具
cd librime
make

# 準备示例文件(有三)
# 做一个构建扩展包专用的方案,以示如何独立於主词典的构建流程。
# 如果不需要把扩展包和主词典分开製备,也可以用原有的输入方案。
cat > build/bin/luna_pinyin_packs.schema.yaml <<EOF
# Rime schema
schema:
  schema_id: luna_pinyin_packs

translator:
  dictionary: luna_pinyin_packs
  packs:
    - sample_pack
EOF

# 代用的主词典。因为本示例只构建扩展包。
# 做这个文件的目的是不必费时地编译导入了预设词汇表的朙月拼音主词典。
# 如果在主词典的构建流程生成扩展包,则可直接使用主词典文件。
cat > build/bin/luna_pinyin_packs.dict.yaml <<EOF
# Rime dict
---
name: luna_pinyin_packs
version: '1.0'
sort: original
use_preset_vocabulary: false
import_tables:
  - luna_pinyin
...

EOF

# 扩展包源文件
cat > build/bin/sample_pack.dict.yaml <<EOF
# Rime dict
---
name: sample_pack
version: '1.0'
sort: original
use_preset_vocabulary: false
...

粗鄙之语	cu bi zhi yu
EOF

# 製作扩展包
(cd build/bin; ./rime_deployer --compile luna_pinyin_packs.schema.yaml)
# 构建完成后可丢弃代用的主词典,只留扩展包
rm build/bin/build/luna_pinyin_packs.*

# 重新配置朙月拼音输入方案,令其加载先时生成的词典扩展包
(cd build/bin; ./rime_patch luna_pinyin 'translator/packs' '[sample_pack]')
# 验证词典可查到扩展包中的词语
echo 'cubizhiyu' | (cd build/bin; ./rime_console)

总结

与编译词典时导入码表的方法相比,使用词典扩展包有两项优势:

  • 扩展包可以独立於主词典及其他扩展包单独构建,增量添加扩展包不必重复编译完整的主词典,减少编译时间及资源开销;
  • 词典扩展包的编译单元与词典源文件粒度一致,方便组合使用,增减扩展包只须重新配置输入方案。

需要注意的是,查询时使用主词典的音节表,这要求扩展包使用相同的音节表构建。 目前 librime 并没有机制保证加载的扩展包与主词典兼容。用家须充分理解该功能的实现机制,保证数据文件的一致性。 这也意味着二进制扩展包不宜脱离於主词典而製作和分发。

定制指南详解

先来一个阅读自检吧~

  • [[#必知必会]]
  • [[#Rime 中的数据文件分布及作用]]
  • [[#方案制作详解]]
  • [[#定制指南]]
patch:
  "一组设定项/二级设定项/三级设定项": 新的设定值
  "另一个设定项": 新的设定值
  "再一个设定项": 新的设定值
  "含列表的设定项/@0": 列表第一个元素新的设定值
  "含列表的设定项/@last": 列表最后一个元素新的设定值
  "含列表的设定项/@before 0": 在列表第一个元素之前插入新的设定值(不建议在补丁中使用)
  "含列表的设定项/@after last": 在列表最后一个元素之后插入新的设定值(不建议在补丁中使用)
  "含列表的设定项/@next": 在列表最后一个元素之后插入新的设定值(不建议在补丁中使用)

定制每页候选数

Rime 中,默认每页至多显示 5 个候选项,而允许的范围是 1~9(个别 Rime 发行版可支持 10 个候选)。

设定每页候选个数的默认值为 9,在用户目录建立文档 default.custom.yaml :

1
2
patch:
  "menu/page_size": 9

重新布置即可生效。

〔注意〕 如果 default.custom.yaml 里面已经有其他设定内容,只要以相同的缩进方式添加 patch: 以下部分,不可重复 patch: 这一行。

若只需要将单独一个输入方案的每页候选数设为 9 ,以朙月拼音为例,建立文档 luna_pinyin.custom.yaml 写入相同内容,重新部署即可生效。

定制标点符号

有的用户习惯以 / 键输入标点

仍以朙月拼音为例,输入方案有以下设定:

1
2
3
4
5
# luna_pinyin.schema.yaml
# ...

punctuator:
  import_preset: default

解释:

punctuator 是 Rime 中负责转换标点符号的组件。该组件会从设定中读取符号映射表,而知道该做哪些转换。

punctuator/import_preset 是说,本方案要继承一组预设的符号映射表,要从另一个设定档 default.yaml 导入。

查看 default.yaml ,确有如下符号表:

1
2
3
4
5
6
7
8
9
punctuator:
  full_shape:
    # ……其他……
    "/" : [ /, "/", ÷ ]
    # ……其他……
  half_shape:
    # ……其他……
    "/" : [ "/", /, ÷ ]
    # ……其他……

可见按键 / 是被指定到  "/", /, ÷ 等一组符号了。并且全角和半角状态下,符号有不同的定义。

欲令 / 键直接输出 ,可如此定制  luna_pinyin.custom.yaml:

1
2
3
4
5
patch:
  punctuator/full_shape:
    "/" : "、"
  punctuator/half_shape:
    "/" : "、"

以上在输入方案设定中写入两组新值,合并后的输入方案成为:

1
2
3
4
5
6
7
8
9
# luna_pinyin.schema.yaml
# ...

punctuator:
  import_preset: default
  full_shape:
    "/" : "、"
  half_shape:
    "/" : "、"

含义是在由 default 导入的符号表之上,覆写对按键 / 的定义。

通过这种方法,即直接继承了大多数符号的默认定义,又做到了局部的修改化。

定制简化字输出

注意,如果你只需要 Rime 输出简化字,敲 Ctrl+~ 组合键,从菜单中选择「漢字→汉字」即可!

本例说明旨在说明其中原理,以及通过设定档修改预设输出字形的方法。

Rime 预设的词汇表中使用传统汉字。这是因为传统汉字较简化字提供了更多信息,做「繁→简」转换能够保证较高的精度。

Rime 中的过滤器组件 simplifier,完成对候选词的繁简转换。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# luna_pinyin.schema.yaml
# ...

switches:
  - name: ascii_mode
    reset: 0
    states: [ 中文, 西文 ]
  - name: full_shape
    states: [ 半角, 全角 ]
  - name: simplification    # 转换开关
    states: [ 漢字, 汉字 ]

engine:
  filters:
    - simplifier            # 必要组件一
    - uniquifier            # 必要组件二

以上是朙月拼音中有关繁简转换功能的设定。

在 engine/filters 中,除了 simplifier,还用了一件 uniquifier。 这是因为有些时候,不同的候选会转化为相同的简化字,例如「鐘→钟」、「鍾→钟」。 uniquifier 的作用是在 simplifier 执行转换之后,将文字相同的候选项合并。

该输入方案设有三个状态开关:中/西文、全/半角、繁简字。即 switches 之下三项。

每个开关可以在两种状态(states)之间转换,simplifier 依据名为 simplification 的开关状态来决定是否做简化:

  • 初始状态下,输出为传统汉字,〔 方案选单 〕中的开关选项显示为「漢字→汉字」;
  • 选择该项后,输出为简化汉字,〔 方案选单 〕中显示 「汉字→漢字」;
  • Rime 会记忆你的选择,下次打开输入法时,直接切换到所选的字形;
  • 亦可无视上次记住的选择,在方案中重设初始值:reset 设为 01,分别选中 states 列表中的两种状态。

如日常应用以简化字为主,则每每在〔 方案选单 〕中切换十分不便。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# luna_pinyin.custom.yaml

patch:
  switches:                   # 注意缩进
    - name: ascii_mode
      reset: 0                # reset 0 的作用是当从其他输入方案切换到本方案时,
      states: [ 中文, 西文 ]   # 重设为指定的状态,而不保留在前一 个方案中设定的状态。
    - name: full_shape         # 选择输入方案后通常需要立即输入中文,故重设 ascii_mode = 0;
      states: [ 半角, 全角 ]   # 而全/半角則可沿用之前方案中的用法。
    - name: simplification
      reset: 1                # 增加这一行:默認啓用「繁→简」转换。
      states: [ 漢字, 汉字 ]

其实预设输入方案中就提供一丈朙月拼音的简化字版本,名为简化字,以应大家“填表”之需。看他的代码如何与上篇定制档写得不同:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# luna_pinyin_simp.schema.yaml
# ...

switches:
  - name: ascii_mode
    reset: 0
    states: [ 中文, 西文 ]
  - name: full_shape
    states: [ 半角, 全角 ]
  - name: zh_simp           # 注意这里(※1)
    reset: 1
    states: [ 漢字, 汉字 ]

simplifier:
  option_name: zh_simp      # 和这里(※2)

前方说,simplifier 这个组件会检查名为 simplification 的开关状态;而这款简化字方案却用了一个不同名的开关 zh_simp ,即  ※1 处所示;并通过在 ※2 行设定  simplifier/option_name 告知  simplifier 组件所需关注的开关名字。

何故?

还记是否,前文对「全/半角」这个开关的讨论 – 当切换方案时,未明确使用 reset 重置的开关,会保持之前设定过的状态。

朙月拼音等多数方案,并未重设  simplification 这个选项 – 因为用户换了一种输入编码的方式,并不意味着需要变更输出的字形。

而简化字这一方案不同,恰恰是表达变更输出字形的需求;用户再从简化字切回朙月拼音时,一定是为了回到繁体输出模式。所以令简化字使用独立命名的开关、而非方案间共用的 simplification 开关,以避免影响其他输入方案的繁简转换状态。

默认英文输出

有些用户习惯默认英文输出,在需要用中文时再做切换。这就需要键们在方案中重设状态开关初始值。

还记得吗?我们可用 reset 设定项在方案中为某些状态开关重设初始值:reset 设为 0 或 1,分别选中 states 列表中的两种状态。

我们以朙月拼音为例:

1
2
3
4
# luna_pinyin.custom.yaml

patch:
  "switches/@0/reset": 1  # 表示将 switcher 列表中的第一个元素(即 ascii_mode 开关)的初始值重設为状态1(即「英文」)。

定制方案选单

在「 小狼毫 」方案选单设定介面上勾勾选选,就可以如此定制输入方案列表:

1
2
3
4
5
6
7
8
9
# default.custom.yaml

patch:
  schema_list:  # 对于列表类型,现在没有办法指定如何添加、消除或单一修改某项,于是要在定制档中将整个列表替换
    - schema: luna_pinyin
    - schema: cangjie5
    - schema: luna_pinyin_fluency
    - schema: luna_pinyin_simp
    - schema: my_coolest_ever_schema  # 这样就启用了未曾有过的高级输入方案,其实这么好的方案应该排在最前面哈

没有设定界面时,又想启用、禁用某个输入方案,手写这样一份定制档,重新部署就好啦。

定制唤出方案选单的快捷键

呼出方案选单,默认快捷键为 Ctrl+~F4

不过有些同学电脑上默认快捷键与其他软件有冲突,那么如何定义更好的键位呢?

1
2
3
4
5
6
7
# default.custom.yaml

patch:
  "switcher/hotkeys":  # 这个列表里第项定义一个快捷键,使哪个都可以
    - "Control+s"      # 添加 Ctrl+s
    - "Control+grave"  # 你看写法并不是 Ctrl+` 而是与 IBus 一致的表示法
    - F4

按键定义的格式为「 修饰符甲 + 修饰符乙 + … + 按键名称 」,加号为分隔符,要写出。

所谓修饰符,就是以下组合键的状态标识或是按键弹起的标识:

  • Release —— 按键被放开,而不是按下;
  • Shift
  • Control
  • Alt——Windows 上 Alt+字母 会被系统优先识别为程序菜单项的快捷键,当然 Alt+Tab 也不可用;
  • 嗯,Linux 发行版还支持 Super, Meta 等組合键,不过最好选每个平台都能用的啦。

按键的名称,大小写字母选数字都用它们自己表示,其他按键名称参考 [[#其它|细项配置-按键]] 章节。

定制小狼毫字体字号

虽然与输入方案无关,也在此列出以作参考。

1
2
3
4
5
# weasel.custom.yaml

patch:
  "style/font_face": "明兰"  # 字体名称,从记事本等处的系统字体对话框里能看到
  "style/font_point": 14     # 字号,只认数字,不认「五号」、「小五」这样的

定制小狼毫配色方案

注:这款配色已经在新版本的小狼毫里预设了,做练习时,你可以将文中  starcraft 换成自己命名的标识。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# weasel.custom.yaml

patch:
  "style/color_scheme": starcraft    # 这项用于选中下面定义的新方案
  "preset_color_schemes/starcraft":  # 在配色方案列表里加入标识为 starcraft 的新方案
    name: 星際我爭霸/StarCraft
    author: Contralisk <contralisk@gmail.com>, original artwork by Blizzard Entertainment
    text_color: 0xccaa88             # 编码行文字顏色,24位色值,用十六进制书写方便些,順序是蓝绿红 0xBBGGRR
    candidate_text_color: 0x30bb55   # 候选项文字颜色,当与文字颜色不同时指定
    back_color: 0x000000             # 底色
    border_color: 0x1010a0           # 边框颜色,与底色相同则为无边框的效果
    hilited_text_color: 0xfecb96     # 高亮文字,即与当前高亮候选对应的那部份输入码
    hilited_back_color: 0x000000     # 设定高亮文字的底色,可起到突显高亮部份的作用
    hilited_candidate_text_color: 0x60ffa8  # 高亮候选项的文字颜色,要醒目!
    hilited_candidate_back_color: 0x000000  # 高亮候选项的底色,若与背景色不同就会显出光棒

效果自己看!

也可以参照这张比较直观的图:

![[assets/Pasted image 20250109111833.png]]

另,此处有现成的配色方案工具供用户调配:

配置文件详解

Rime 配置文件,用於设置输入法引擎、输入法客户端的运行参数,也包括输入方案及词典配置。

文件格式:採用 UTF-8 编码的 YAML 文本。

位置及组织方式: Rime 所使用的配置文件在 用户文件夹 及 共享文件夹。

语法

在 YAML 语法的基础上,增设以下编译指令:

包含

__include: 指令在当前位置包含另一 YAML 节点的内容。

可写在配置源文件任一 YAML map 节点下。其语法为

include_example_1:
  __include: local/node

local:
  node: contents to include

被引用的节点可以来自另一个配置文件。 目标配置节点的路径以 <filename>:/ 开始,可省略扩展名 .yaml

include_example_2:
  __include: config:/external/node

include_example_3:
  __include: config.yaml:/external/node

包含整个文件,可指定路径为目标配置文件的根节点:

include_example_4:
  __include: config.yaml:/

包含另一个 YAML map 节点后,源文件中 __include: 指令所在 map 除编译指令外的其他数据与被包含的 map 合併:

include_example_5:
  __include: some_map
  occupation: journalist # new key and value
  simplicity: very # override value for included key

some_map:
  simplicity: somewhat
  naivety: sometimes

合併发生在 __include: 指令所在节点,不会修改被引用节点 some_map 的内容。

包含 YAML 列表,则指令所在 map 节点替换为所引用的 YAML 列表。 该 map 节点不应包含任何编译指令以外的 key-value,因为不相容於 YAML 列表类型。

也不能直接在该节点下追加列表项,因为 YAML 语法不允许混合 map 与 list。 在包含列表后追加、修改列表项,必须使用下文介绍的 __append:__patch: 指令。

include_example_6:
  __include: some_list
  __append:
    - someone else

some_list:
  - youngster
  - elder

补靪

修改某一相对路径下的配置节点,而非当前节点的整体。 基本语法为:

__patch:
  key/alpha: value A
  key/beta: value B

目标节点路径的写法为将各级 map 的 key 用 / 分隔。 因此 key 如果包含 / 字符,则不能作为节点路径的一部分。

可在节点路径末尾添加 /+ 操作符,表示合併 list 或 map 节点; 或者(可选地)添加 /= 表示用指定的值替换目标节点原有的值。 若未指定操作符,__patch: 指令的默认操作为替换。

以下是一些示例:

patch_example_1:
  sibling: old value
  append_to_list:
    - existing item
  merge_with_map:
    key: value
  replace_list:
    - item 1
    - item 2
  replace_map:
    a: value
    b: value
  __patch:
    sibling: new value
    append_to_list/+:
      - appended item
    merge_with_map/+:
      key: new value
      new_key: value
    replace_list/=:
      - only item
    replace_map/=:
      only_key: value

以上示例仅为表现 __patch: 的作用方式。 实际上在当前节点和补靪内容均为字面值的情况下,没有打补靪的必要。 字面值补靪通常用於当前节点包含了其他节点,并需要修改部份配置项的场景:

patch_example_2:
  __include: patch_example_1
  __patch:
    sibling: even newer value
    append_to_list/+:
      - another appended item

由於 YAML map 的 key 是无序的,书写顺序并不决定编译指令的先后。

同一节点下,编译指令的执行顺序为: __include: 包含指定节点 → 合併当前节点下的其他 key-value 数据 → __patch: 修改子节点。

__patch: 指令的另一种主要用法是引用另一个节点中的补靪内容,并作用於指令所在节点:

patch_example_3:
  __patch: changes
  some_list:
    - youngster
    - elder
  some_map:
    simplicity: somewhat
    naivety: sometimes

changes:
  some_list/+:
    - someone else
  some_map/simplicity: too much

YAML 语法不允许 map 有重复的 key。 如果要引用不同位置的多项补靪,可以为 __patch: 指定一个列表,其中每项通过节点引用定义一组补靪:

patch_example_4:
  __include: base_config
  __patch:
    - company_standard
    - team_convention
    - personal_preference

base_config:
  actors: []
  company_info:
    based_in: unknown location
  favorites: {}

company_standard:
  company_info/based_in: american san diego

team_convention:
  actors/+:
    - feifei
    - meimei
    - riri

personal_preference:
  favorites/fertilizer: jinkela

用补靪指令修改列表

补靪指令中,目标节点路径由各级节点的 key 组成。 若某一节点为 list 类型,可以 @<下标> 形式指定列表项。下标从 0 开始计数。 无论列表长度,末位列表元素可表示为 @last。

patch_list_example_1:
  some_list/@0/simplicity: very
  some_list/@last/naivety: always

some_list:
  - simplicity: somewhat
  - naivety: sometimes

在指定元素之前、之后插入列表元素,用 @before <下标>、@after <下标>。 @after last 可简写为 @next,向列表末尾添加元素:

patch_list_example_2:
  'some_list/@before 0/youthfulness': too much
  'some_list/@after last/velocity': greater than westerners
  some_list/@next/questions: no good

可选的包含与补靪

若包含或补靪指令的目标是以 ? 结尾的节点路径, 则当该路径对应的节点(或所属外部配置文件)不存在时,不產生编译错误。

如:

__patch: default.custom:/patch?

nice_to_have:
  __include: optional_config?

追加与合併

追加指令 __append: 将其下的列表项追加到该指令所在的节点。 合併指令 __merge: 将其下的 map 合併到该指令所在的节点。

这两条指令只能用在 __include: 指令所在节点及其(字面值)子节点。

append_merge_example_1:
  __include: starcraft
  __merge:
    made_by: blizzard entertainment
    races:
      __append:
        - protoss
        - zerg

starcraft:
  first_release: 1998
  races:
    - terrans

实际书写配置时,__merge: 指令往往省略。 因为 __include: 指令自动合併其所在节点下的 key-value 并递归地合併所有 map 类型的子节点。

而对於类型为 list 的子节点,默认操作是替换整个列表。 如果要以向后追加列表项的方式合併,除了 __append: 指令之外,还可以採用 /+ 操作符:

append_merge_example_2:
  __include: starcraft
  made_by: blizzard entertainment
  races/+:
    - protoss
    - zerg

__include: 指令自动合併的节点树中,如果要对某个 map 类型的子节点整体替换,可使用 /= 操作符:

revealed_map:
  __include: old_map
  terran_command_center/=:
    x: 3.14
    y: 6.28
old_map:
  terran_command_center:
    location: unexplored
  protoss_nexus: {x: 128, y: 256}
  zerg_hatchary: {x -1024, y: 0}

案例解析:

https://github.com/rime/librime/pull/192#issuecomment-371202389

配置编译器插件

自动添加一些隐含的编译指令,用来实现对原有补靪机制以及导入成套组件配置等语法的兼容。

这些插件的作用是将当前输入方案所需的全部配置内容在部署期间汇总到一份编译结果文件里。使输入法程序不必在运行时打开众多的配置文件。

自动应用补靪

配置文件的根节点如果没有使用 __patch: 指令,则在源文件编译完成后,自动插入以下指令:

(註:请将实际的配置名称代入 <config>

# <config>.yaml 或 <config>.schema.yaml 的根节点
__patch: <config>.custom:/patch?

如果存在与旧版本 librime 兼容的补靪文件,则从中加载补靪:

# <config>.custom.yaml
patch:
  key: value

以上插件的效果相当於

# <config>.yaml 或 <config>.schema.yaml 的根节点
__patch:
  key: value

如果源文件的根节点使用了 __patch: 指令,则不论其是否加载 <config>.custom:/patch,都不再添加自动补靪指令。 如果这种情况下仍希望支持补靪文件,须将其列为 __patch: 列表中的一项:

# <config>.yaml 或 <config>.schema.yaml 的根节点
__patch:
  - other_patch # ...
  - <config>.custom:/patch?

应用默认配置

输入方案中未指定以下配置项时,自动导入默认配置 default.yaml 的定义:

menu:
  page_size: # ...

导入成套组件配置

将部份组件配置中的 <component>/import_preset: <config> 语法翻译为

(註:请将实际的配置名称和组件名称代入 <config>、<component>

<component>:
  __include: <config>:/<component>
  # 以下为输入方案覆盖定义的内容

注意:如果指定的配置节点 <config>:/<component> 不存在会导致输入方案编译错误。

导入韵书配置 (尚未实现)导入 *.dict.yaml 的 YAML 配置部份。

加载规则

以上介绍的编译指令及编译器插件,仅对交给 配置编译器 处理的 源文件 有效。

配置源文件的位置详见 用户文件夹 及 共享文件夹。

输入法程序运行时读取的配置文件是 编译结果文件(可能是 YAML 格式或二进制格式)。 编译结果只包含直接供程序读取的配置内容,而不再包含有特殊含义的编译指令。

配置的编译结果文件与源文件并非一一对应的关系, 而是合併重组为编译后的默认配置 default 以及各输入方案的配置。

其他不经过编译处理而直接在运行时由输入法程序存取的配置文件有: installation.yaml, user.yaml 等。

韵书 文件中的 YAML 配置部份目前也不支持配置编译指令。

TODO(rime/docs): 详解 YAML 节点树及编译指令的解析、执行顺序。

配置组件调用方式

TODO(rime/engine): 完成本节

代码风格

YAML 书写样式参照 yaml.org 的示例。推荐以下风格:

配置文件开头用註释行简述文件的内容和使用方法。

缩进:用两个空格缩进。

字符串值:无特殊字符时不使用引号; 需要使用引号时,优先用单引号,以减少双引号引起的字符转义问题。

flow-style list: 仅在节点树的最内层使用。不嵌套使用。元素较多时不用。

flow-style map: 仅在节点树的最内层使用。不嵌套使用。元素较多时不用。

仅包含一对 key-value 的 map 作为列表项时,省略 { } 并与 - 写在同一行。

不推荐使用 YAML 的锚点(&)和别名引用(*)。请用本文介绍的 __include: 编译指令。

错误处理

部署后出现错误,请查看 INFO 日誌(参考), 找到行首字符为 E 的记录,根据错误信息以及上下文排查出错的配置文件。

未出现错误信息,配置亦未达到预期效果,请对照 <用户文件夹>/build/ 文件夹内的编译结果文件,检查配置源文件与补靪。

版本控制

输入方案及配置的版本可以用文件中的一项 字符串值 记录。如:version: ‘3.14’

版本号习惯以形为 X.Y.Z 的多个数字组成。 为避免将版本号解析为 YAML 数值类型而发生错误,如 0.10(〇点十)不同於 0.1(〇点一), 应一律为版本号加上引号 ‘3.14’ 以示其为字符串类型。

分发

输入方案设计师完成输入方案及配套韵书后,将源文件发佈在一间 GitHub 代码库, 用家便可通过 Rime 配置管理工具 东风破 获取输入方案的最新版本并安装到输入法。

DIY 处方集

已将一些定制 Rime 的常见问题、解法及定制档链接收录于此。

建议你首先读完《 定制指南 》,通晓相关原理,以正确运用这些处方。

初始设定

在方案选单中添加五笔、双拼

https://gist.github.com/2309739

在 Rime 输入方案选单中添加五笔、双拼、粤拼、注音,保留你需要的。

# default.custom.yaml
# save it to: 
#   ~/.config/ibus/rime  (linux)
#   ~/Library/Rime       (macos)
#   %APPDATA%\Rime       (windows)

patch:
  schema_list:
    - schema: luna_pinyin          # 朙月拼音
    - schema: luna_pinyin_simp     # 朙月拼音 简化字模式
    - schema: luna_pinyin_tw       # 朙月拼音 臺灣正體模式
    - schema: terra_pinyin         # 地球拼音 dì qiú pīn yīn
    - schema: bopomofo             # 注音
    - schema: bopomofo_tw          # 注音 臺灣正體模式
    - schema: jyutping             # 粵拼
    - schema: cangjie5             # 倉頡五代
    - schema: cangjie5_express     # 倉頡 快打模式
    - schema: quick5               # 速成
    - schema: wubi86               # 五笔86
    - schema: wubi_pinyin          # 五笔拼音混合輸入
    - schema: double_pinyin        # 自然碼雙拼
    - schema: double_pinyin_mspy   # 微軟雙拼
    - schema: double_pinyin_abc    # 智能ABC雙拼
    - schema: double_pinyin_flypy  # 小鶴雙拼
    - schema: wugniu               # 吳語上海話(新派)
    - schema: wugniu_lopha         # 吳語上海話(老派)
    - schema: sampheng             # 中古漢語三拼
    - schema: zyenpheng            # 中古漢語全拼
    - schema: ipa_xsampa           # X-SAMPA 國際音標
    - schema: emoji                 # emoji表情

看这个例子,可以应用任一预设或自定义输入方案,如【粵拼】、【注音】等。(详解:参见前方 [[#定制方案选单]] 一节)。

如果下载自己制作了非预设输入方案,将源文件复制到用户文件夹后,也用上面的方法将方案标识加入选单。

修改后重新部署生效。

【小狼毫】外观设定

上文已介绍设定字体、字号、制作配色方案的方法。

使用横向候选栏,嵌入式编码行:

1
2
3
4
5
# weasel.custom.yaml
patch:
  style/horizontal: true         # 候选橫排
  style/inline_preedit: true     # 內嵌编码(仅支持TSF)
  style/display_tray_icon: true  # 显示托盘图标

【鼠须管】外观与键盘设定

鼠须管从 0.9.6 版本开始支持选择配色方案,用  squirrel.custom.yaml 保存用户的设定。

https://gist.github.com/2290714

> 【鼠鬚管】定製檔

# 適用於【鼠鬚管】0.9.13+
# 位置:~/Library/Rime/squirrel.custom.yaml
# 用法:想要哪項生效,就刪去該行行首的#字符,但注意保留用於縮進的空格

patch:
#  us_keyboard_layout: true      # 鍵盤選項:應用美式鍵盤佈局
#  show_notifications_when: growl_is_running  # 狀態通知,默認裝有Growl時顯示,也可設爲全開(always)全關(never)
#  style/horizontal: true        # 候選窗横向顯示
#  style/inline_preedit: false   # 非內嵌編碼行
#  style/font_face: "儷黑 Pro"    # 我喜歡的字體名稱
#  style/font_point: 21          # 字號
#  style/corner_radius: 10       # 窗口圓角半徑
#  style/border_height: 0        # 窗口邊界高度,大於圓角半徑才有效果
#  style/border_width: 0         # 窗口邊界寬度,大於圓角半徑才有效果
#  style/color_scheme: luna      # 選擇配色方案

# 註:預設的配色方案及代碼(指定爲 style/color_scheme )
#   系統默認色系 - native
#   碧水 - aqua
#   青天 - azure
#   明月 - luna
#   墨池 - ink
#   孤寺 - lost_temple
#   暗堂 - dark_temple
#   星際我爭霸 - starcraft
#   谷歌 - google
#   曬經石 - solarized_rock
#   简约白 - clean_white

ibus用户: ibus_rime.custom.yaml 不包含控制配色、字体字号等外观样式的设定。

在特定程序里开关中文输入

【鼠须管】0.9.9 开始支持这项设定:

这指定的应用程序中,改变输入法的初始转换状态。如在:

  • 终端 Terminal / iTerm
  • 代码编辑器 MacVim
  • 快速启动工具 QuickSilver / Alfred 等程序里很少需要輸入中文,于是鼠须管在這些程序里置信不开启中文输入。

自定义 Mac 应用程序的初始转换状态,首先查看应用的 Info.plist 文件得到该应用的  Bundle Identifier,通常是形如 com.apple.Xcode 的字符串。

例如,要在 Xcode 里面默认开关中文输入,又要在 Alfred 里面恢复开启中文输入,可如此设定:

1
2
3
4
5
# example squirrel.custom.yaml
patch:
  app_options/com.apple.Xcode:
    ascii_mode: true
  app_options/com.alfredapp.Alfred: {}

注:一些版本的 Xcode 标识为 com.apple.dt.Xcode,请注意查看 Info.plist

【小狼毫】0.9.16 亦开始支持这项设定。

例如,要在 gVim 里面默认开关中文输入,可如此设定:

1
2
3
4
# example weasel.custom.yaml
patch:
  app_options/gvim.exe:  # 程序名字全用小写字母
    ascii_mode: true

输入习惯

使用 Control 键切换中西文

https://gist.github.com/2981316

> 使用 Control 键切换中西文,上屏已输入的编码;令 Caps Lock 改变字母的大小写

# 中西文切换键的默认设置写在 default.yaml 里面
# 以下的 default.custom.yaml 在全局范围重定义该组快速键
#
# 可用的按键有 Caps_Lock, Shift_L, Shift_R, Control_L, control_R
# Mac 系统上的鼠鬚管不能区分左、右,因此只有对 Shift_L, Control_L 的设定起作用
#
# 已输入编码时按切换键,可以进一步设定输入法中西文切换的形式。
# 可选的临时切换策略有三:
# inline_ascii 在输入法的临时西文编辑区内输入字母、数字、符号、空格等,回车上屏后自动复位到中文
# commit_text 已输入的候选文字上屏并切换至西文输入模式
# commit_code 已输入的编码字符上屏并切换至西文输入模式
# 设为 noop,屏蔽该切换键
#
# 如果要把 Caps Lock 设为只改变字母的大小写而不做中西文切换,可将 Caps_Lock 对应的切换方式设为 noop
# 如果要以 Caps Lock 切换到西文模式,默认输出小写字母,请置 ascii_composer/good_old_caps_lock: false
# 如果要以 Caps Lock 切换到西文模式,默认输出大写字母,请使用以下设置:

patch:
  ascii_composer/good_old_caps_lock: true
  ascii_composer/switch_key:
    Caps_Lock: commit_code
    Shift_L: noop
    Shift_R: noop
    Control_L: commit_code
    Control_R: commit_code

以及修改 Caps Lock、左右 Shift、左右 Control 键的行为,提供三种切换方式。 详見 Gist 代码注释。

方便地输入含数字的西文用戶名

通常,输入以小写拉丁字母组成的编码后,数字键的作用是选择相应序号的候选字。

假设我的邮箱地址是  rime123@company.com,则需要在输入 Rime 之后上屏或做临时中西文切换,方便可输入数字部分。

为了更方便输入我的用户名 rime123,设置一组特例,将 rime 与其后的数字优先识别西文。

https://gist.github.com/3076166

> 自动识别西文及数字组成的用户名

# default.custom.yaml
# 全局范围识别输入串为 rime + 任意数字序列,以及形如 rimeime-1.2.3 的常用西文短语
# 也可将本组 patch 写入 <输入方案ID>.custom.yaml 使这组规则仅在一款输入方案中有效
#
# 第一例,输入 rime 之后,再输入任意一个数字,则立即识别为西文输入
# 再加上 default.yaml 原有的 email 规则,识别包含 @ 字符的邮箱,於是可以一气呵成 rime123@company.com 
# 第二例,输入到 rimeime 时,立即识别为西文输入,并可跟随任意位数字及指定的符号

patch:
  recognizer/patterns/rime123: "^rime[0-9]+$"
  recognizer/patterns/rimeime: "^rimeime[-_.0-9]*$"

以方括号键换页

https://gist.github.com/2316704

在 Rime 中加入"[“和”]“翻页按键绑定(以【明月拼音】为例)

# luna_pinyin.custom.yaml
# save it to: 
#   ~/.config/ibus/rime  (linux)
#   ~/Library/Rime  (macos)
#   %APPDATA%\Rime  (windows)

patch:
  "key_binder/bindings":
    - { when: paging, accept: bracketleft, send: Page_Up }
    - { when: has_menu, accept: bracketright, send: Page_Down }

添加 Mac 风格的翻页键 [ ] 。这是比较直接的设定方式。下一则示例给出了麦种更系统、可重用的设定方式。

使用西文标点兼以方括号键换页

https://gist.github.com/2334409

> Rime 别样设定,使用西文标点、[]键换页

# Rime alternative settings
# encoding: utf-8
#
# difference from default settings:
# 1. ascii-style punctuation in half-shape mode
# 2. [ ] as paging keys
#
# save this file as:
# (Linux)   ~/.config/ibus/rime/alternative.yaml
# (Mac OS)  ~/Library/Rime/alternative.yaml
# (Windows) "%APPDATA%\Rime\alternative.yaml"
# 
# edit <SCHEMA_ID>.custom.yaml:
# >> patch:
# >>   'punctuator/import_preset': alternative
# >>   'key_binder/import_preset': alternative
#
# for detailed explanation, refer to:
# http://code.google.com/p/rimeime/wiki/CustomizationGuide#%E4%BD%BF%E7%94%A8%E5%85%A8%E5%A5%97%E8%A5%BF%E6%96%87%E6%A8%99%E9%BB%9E 

config_version: "0.3"

punctuator:
  full_shape:
    " " : { commit: " " }
    "," : { commit: , }
    "." : { commit: 。 }
    "<" : [ 《, 〈, «, ‹ ]
    ">" : [ 》, 〉, », › ]
    "/" : [ 、, /, "/", ÷ ]
    "?" : { commit: ? }
    ";" : { commit: ; }
    ":" : :
    "'" : { pair: [ "‘", "’" ] }
    "\"" : { pair: [ "“", "”" ] }
    "\\" : [ 、, \, "\\" ]
    "|" : [ ・, |, "|", "§", "¦" ]
    "`" : [ `, "`" ]
    "~" : [ 〜, "~", ~, 〰 ]
    "!" : { commit: ! }
    "@" : [ @, "@", ☯ ]
    "#" : [ #, "#", ⌘ ]
    "%" : [ %, "%", "°", "℃" ]
    "$" : [ ¥, "$", "€", "£", "¥", "¢", "¤" ]
    "^" : { commit: …… }
    "&" : [ &, "&" ]
    "*" : [ *, "*", ・, ×, ※, ❂, · ]
    "(" : (
    ")" : )
    "-" : [ -, "-" ]
    "_" : ——
    "+" : [ +, "+" ]
    "=" : [ =, "=" ]
    "[" : [ 「, 【, 〔, [ ]
    "]" : [ 」, 】, 〕, ] ]
    "{" : [ 『, 〖, { ]
    "}" : [ 』, 〗, } ]
  half_shape:
    "," : { commit: "," }
    "." : { commit: "." }
    "<" : "<"
    ">" : ">"
    "/" : "/"
    "?" : { commit: "?" }
    ";" : { commit: ";" }
    ":" : { commit: ":" }
    "'" : "'"
    "\"" : "\""
    "\\" : "\\"
    "|" : "|"
    "`" : "`"
    "~" : "~"
    "!" : { commit: "!" }
    "@" : "@"
    "#" : "#"
    "%" : "%"
    "$" : "$"
    "^" : "^"
    "&" : "&"
    "*" : "*"
    "(" : "("
    ")" : ")"
    "-" : "-"
    "_" : "_"
    "+" : "+"
    "=" : "="
    "[" : "["
    "]" : "]"
    "{" : "{"
    "}" : "}"

key_binder:
  bindings:
    # commonly used paging keys
    - { when: composing, accept: ISO_Left_Tab, send: Page_Up }
    - { when: composing, accept: Shift+Tab, send: Page_Up }
    - { when: composing, accept: Tab, send: Page_Down }
    - { when: has_menu, accept: minus, send: Page_Up }
    - { when: has_menu, accept: equal, send: Page_Down }
    - { when: paging, accept: comma, send: Page_Up }
    - { when: has_menu, accept: period, send: Page_Down }
    - { when: paging, accept: bracketleft, send: Page_Up }
    - { when: has_menu, accept: bracketright, send: Page_Down }

详见上文「使用全套西文标点」一节。

以回车键清除编码兼以分号、单引号选字

https://gist.github.com/2390510

> Rime 设定:以回车清除编码串,分号、单引号键选择 2、3 候选

# cangjie5.custom.yaml
# save it to:
# ~/.config/ibus/rime (linux)
# ~/Library/Rime (macos)
# %APPDATA%\Rime (windows)

patch:
  "key_binder/bindings":
    - { when: composing, accept: Return, send: Escape }
    - { when: has_menu, accept: semicolon, send: 2 }
    - { when: has_menu, accept: apostrophe, send: 3 }

适合一些形码输入法(如五笔、郑码)的快手。

开关逐键提示

table_translator 默认开启逐键提示。若要只出精确匹配输入码的候选字,可关闭这一选项。

以【仓颉五代】为例:

1
2
3
# cangjie5.custom.yaml
patch:
  translator/enable_completion: false

关闭用戶词典和字频调整

以【五笔 86】为例:

1
2
3
# wubi86.custom.yaml
patch:
  translator/enable_user_dict: false

关闭码表输入法连打

注:这个选项仅针对 table_translator,用于屏蔽仓颉、五笔中带有太级图章「☯」的连打词句选项,不可作用于拼音、注音、速成等输入方案。

以「 仓颉 」为例:

1
2
3
# cangjie5.custom.yaml
patch:
  translator/enable_sentence: false

开关仓颉与拼音混打

默认,给出仓颉与拼音候选的混合列表。

如此设定,直接敲字母只认作仓颉码,但仍可在敲 ~ 之后输入拼音:

1
2
3
# cangjie5.custom.yaml
patch:
  abc_segmentor/extra_tags: {}

空码时按空格键清空输入码

首先需要关闭码表输入法连打(参见上文),这样才可以在打空时不出候选词。

然后设定(以五笔 86 为例):

1
2
3
4
5
6
# wubi86.custom.yaml
patch:
  translator/enable_sentence: false
  key_binder/bindings:
    - {when: has_menu, accept: space, send: space}
    - {when: composing, accept: space, send: Escape}

模糊音

【朙月拼音】模糊音定制模板

https://gist.github.com/2320943

> 朙月拼音 模糊音定制模板

# luna_pinyin.custom.yaml
#
# 【朙月拼音】模糊音定製模板
#   佛振配製 :-)
#
# 位置:
# ~/.config/ibus/rime  (Linux)
# ~/Library/Rime  (Mac OS)
# %APPDATA%\Rime  (Windows)
#
# 於重新部署后生效
#

patch:
  'speller/algebra':
    - erase/^xx$/                      # 第一行保留

    # 模糊音定义
    # 需要哪组就删去行首的 # 号,单双向任选
    #- derive/^([zcs])h/$1/             # zh, ch, sh => z, c, s
    #- derive/^([zcs])([^h])/$1h$2/     # z, c, s => zh, ch, sh

    #- derive/^n/l/                     # n => l
    #- derive/^l/n/                     # l => n

    # 这两组一般是单向的
    #- derive/^r/l/                     # r => l

    #- derive/^ren/yin/                 # ren => yin, reng => ying
    #- derive/^r/y/                     # r => y

    # 下面 hu <=> f 这组写法复杂一些,分情况讨论
    #- derive/^hu$/fu/                  # hu => fu
    #- derive/^hong$/feng/              # hong => feng
    #- derive/^hu([in])$/fe$1/          # hui => fei, hun => fen
    #- derive/^hu([ao])/f$1/            # hua => fa, ...

    #- derive/^fu$/hu/                  # fu => hu
    #- derive/^feng$/hong/              # feng => hong
    #- derive/^fe([in])$/hu$1/          # fei => hui, fen => hun
    #- derive/^f([ao])/hu$1/            # fa => hua, ...

    # 韵母部份
    #- derive/^([bpmf])eng$/$1ong/      # meng = mong, ...
    #- derive/([ei])n$/$1ng/            # en => eng, in => ing
    #- derive/([ei])ng$/$1n/            # eng => en, ing => in

    # 样例足够了,其他请自己总结……

    # 反模糊音?
    # 谁说方言没有普通话精确、有模糊音,就能有反模糊音。
    # 示例为分尖团的中原官话:
    #- derive/^ji$/zii/   # 在设计者安排下鳩佔鹊巢,尖音i只好双写了
    #- derive/^qi$/cii/
    #- derive/^xi$/sii/
    #- derive/^ji/zi/
    #- derive/^qi/ci/
    #- derive/^xi/si/
    #- derive/^ju/zv/
    #- derive/^qu/cv/
    #- derive/^xu/sv/
    # 韵母部份,只能从大面上覆盖
    #- derive/^([bpm])o$/$1eh/          # bo => beh, ...
    #- derive/(^|[dtnlgkhzcs]h?)e$/$1eh/  # ge => geh, se => sheh, ...
    #- derive/^([gkh])uo$/$1ue/         # guo => gue, ...
    #- derive/^([gkh])e$/$1uo/          # he => huo, ...
    #- derive/([uv])e$/$1o/             # jue => juo, lve => lvo, ...
    #- derive/^fei$/fi/                 # fei => fi
    #- derive/^wei$/vi/                 # wei => vi
    #- derive/^([nl])ei$/$1ui/          # nei => nui, lei => lui
    #- derive/^([nlzcs])un$/$1vn/       # lun => lvn, zun => zvn, ... 
    #- derive/^([nlzcs])ong$/$1iong/    # long => liong, song => siong, ...
    # 这个办法虽从拼写上做出了区分,然而受词典制约,候选字仍是混的。
    # 只有真正的方音输入方案纔能做到!但「反模糊音」这个玩法快速而有效!

    # 模糊音定义先於简拼定义,方可令简拼支持以上模糊音
    - abbrev/^([a-z]).+$/$1/           # 简拼(首字母)
    - abbrev/^([zcs]h).+$/$1/          # 简拼(zh, ch, sh)

    # 以下是一组容错拼写,《汉语拼音》方案以前者为正
    - derive/^([nl])ve$/$1ue/          # nve = nue, lve = lue
    - derive/^([jqxy])u/$1v/           # ju = jv,
    - derive/un$/uen/                  # gun = guen,
    - derive/ui$/uei/                  # gui = guei,
    - derive/iu$/iou/                  # jiu = jiou,

    # 自动纠正一些常见的按键错误
    - derive/([aeiou])ng$/$1gn/        # dagn => dang 
    - derive/([dtngkhrzcs])o(u|ng)$/$1o/  # zho => zhong|zhou
    - derive/ong$/on/                  # zhonguo => zhong guo
    - derive/ao$/oa/                   # hoa => hao
    - derive/([iu])a(o|ng?)$/a$1$2/    # tain => tian

  # 分尖团后 v => ü 的改写条件也要相应地扩充:
  #'translator/preedit_format':
  #  - "xform/([nljqxyzcs])v/$1ü/"

【明月拼音·简化字/臺灣正體/语句流】也適用, 只需将模板保存到 luna_pinyin_simp.custom.yaml 、 luna_pinyin_tw.custom.yaml 或 luna_pinyin_fluency.custom.yaml 。

对比模糊音定制模板与 【朙月拼音】方案原件, 可见模板的做法是,在 speller/algebra 原有的规则中插入了一些定义模糊音的代码行。

类似方案如双拼、粤拼等可参考模板演示的方法改写 speller/algebra 。

【吳語】模糊音定制模板

https://gist.github.com/2015335

> Rime 吴语输入方案模糊音定制档

# 文件名: wugniu.custom.yaml
# 为 wugniu.schema.yaml 打补靪
# #号为註释符号,要是不需要开始某一行模糊功能请在该行前头加#号,要是需要该行模糊功能请去掉前面#号。注意要使用的行的对齐。
patch:
  "speller/algebra":
    - abbrev/^([bcdfghjklprstvwxyz]).+$/$1/       # 对齐标準行
    - derive/^tzi/ci/                             # 以下四行是模糊分尖团音
    - derive/^tsi/chi/
    - derive/^zi/ji/
    - derive/^si/xi/
    - derive/^(ch|d?j|gn|x|y)i([aeou])/$1$2/      # 本行不要改动
    - derive/^tzyu/tzy/                           # 以下四行是模糊“书”“诗”
    - derive/^tsyu/tsy/
    - derive/^zyu/zy/
    - derive/^syu/sy/
    - derive/(.*)ij/$1i/                          # 模糊“烟”“衣”
    - derive/(.*)iaq/$1iq/                        # 模糊“约”“一”
    - derive/^yaq/yiq/                            # 模糊“药”“页”
    - derive/(.*)aon/$1an/                        # 模糊前后an
    - derive/(.*)aq/$1eq/                         # 模糊“搭”“得”
    - derive/(.*)eq/$1aq/
    - derive/^yeu/yu/                             # 模糊“远”“与”
    - derive/(.*)ieu/$1iu/                        # 模糊“宛”“餵”
    - derive/^vu/wu/                              # 模糊“无”“何”
    - derive/(.*)ueu/$1eu/                        # 模糊“碗”“按”
    - derive/^weu/reu/                            # 模糊“换”“汗”
    #- derive/^au/u/                               # 模糊“查”“坐”

编码反查

设定【速成】的反查码为粵拼

https://gist.github.com/2944320

> Rime 定制档:设定「 速成 」的反查码为粤拼

# 将反查词典改为粤拼。
# 注意【速成】支持全码、简码混合输入,反查出来的实为仓頡全码。

patch:
  reverse_lookup/dictionary: jyutping
  reverse_lookup/tips: 〔粤拼〕
  reverse_lookup/preedit_format: []

设定【仓颉】的反查码为双拼

https://gist.github.com/2944319

> Rime 定制档:设定「 仓颉 」的反查码为双拼

# 因为【双拼】使用的词典就是【朙月拼音】的词典,所以输入方案中原有的
# reverse_lookup/dictionary: luna_pinyin 保持不变,另外指定一项 prism

patch:
  reverse_lookup/prism: double_pinyin
  reverse_lookup/tips: 〔双拼〕
  reverse_lookup/preedit_format: []

在 Mac 系统上输入 emoji 表情

以下配置方法已过时,新的 emoji 用法见 https://github.com/rime/rime-emoji

五笔简入繁出

【小狼毫】用家请到 下载页取得「扩展方案集」。

安裝完成后,执行输入法设定,添加【五筆·簡入繁出】输入方案。

其他版本请参考这篇说明:

https://gist.github.com/3467172

> README

一,安装简体->繁体映射码表:(该项目由opencc维护:http://code.google.com/p/opencc)
文件1:http://code.google.com/p/rimeime/source/browse/trunk/misc/opencc/data/simp_to_trad_characters.ocd
文件2:http://code.google.com/p/rimeime/source/browse/trunk/misc/opencc/data/simp_to_trad_phrases.ocd
安装位置:共享资料目录
如:/Library/Input Methods/Squirrel.app/Contents/SharedSupport/opencc

二,添加opencc简繁配置文件:
详见:zhs2zht.ini
安装位置:共享资料目录
如:/Library/Input Methods/Squirrel.app/Contents/SharedSupport/opencc

三,自定义五笔拼音输入法配置(同时可用於86版,本文仅提供五笔拼音配置文件)
详见:wubi_pinyin.custom.yaml
安装位置:用户资料目录
如:~/Library/Rime

> wubi_pinyin.custom.yaml

patch:
  switches:
    - name: ascii_mode
      reset: 0
      states: [ 中文, 西文 ]
    - name: full_shape
      states: [ 半角, 全角 ]
    - name: simplification
      states: [ 漢字, 汉字 ]

  simplifier/opencc_config: zhs2zht.ini

  engine/filters:
    - simplifier
    - uniquifier

> zhs2zht.ini

; Open Chinese Convert
;
; Copyright 2010 BYVoid <byvoid.kcp@gmail.com>
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;      http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.

title = simp_to_trad
description = Standard Configuration for Conversion from Simplified Chinese to Traditional Chinese
dict0 = OCD opencc/simp_to_trad_phrases.ocd
dict0 = OCD opencc/simp_to_trad_characters.ocd

修正不对称繁简字

繁→简即时转换比简体转繁体要轻松许多,却也免不了个别的错误。

比如这一例,「 乾 」字是一繁对多简的典型。由它组成的常用词组,opencc 做了了仔细分辨。但是遇到比较生僻的词组、专名,就比较头疼:

http://tieba.baidu.com/p/1909252328

活用标点创建自定义词组

在【朙月拼音】里添加一些自定义文字、符号。可以按照上文设定「 emoji 表情 」的方式为自定义词组创建一个专门的词典。

可是建立词典稍显繁琐,而活用自定义标点,不失为一个便捷的方法:

1
2
3
4
5
6
7
8
# luna_pinyin.custom.yaml
# 如果不需要 `键的仓颉反查拼音功能,則可利用 ` 键输入自定义词组
patch:
  recognizer/patterns/reverse_lookup:
  'punctuator/half_shape/`':
    - '佛振 <chen.sst@gmail.com>'
    - 'http://rime.github.io'
    - 上天赋予你高的智商,教你用到有用的地方。

上例 recognizer/patterns/reverse_lookup: 作用是开关 ~ 键的反查功能。若选用其他符号则不需要这行。又一例:

1
2
patch:
  'punctuator/half_shape/*': '*_*'

'punctuator/half_shape/*' 因为字符串包含符号,最好用 单引号 括起來;尽量不用双引号以避免符号的转义问题。

然而,重定义「/」「+」「=」这些符号时,因其在节点路径中有特殊含义,无法用上面演示的路径连写方式。因此对于标点符号,推荐的定制方法为在输入方案里覆盖定义 half_shape 或 full_shape 节点:

1
2
3
4
5
patch:
  punctuator/half_shape:
   '/': [ '/', '/hello', '/bye', '/* TODO */' ]
   '+': '+_+'
   '=': '=_='

附录

五笔码表开头的那些属性是什么意思

---
name: wubi86                      # 码表名称
version: "0.7"                    # 版本号
sort: by_weight                   # 词条按权重排序
columns:                          # 定义了数据表中每一列的含义
  - text                          # ... 字词
  - code                          # ... 对应的五笔编码
  - weight                        # ... 词条权重(用于排序和优先级)
  - stem                          # ... 词干编码(可能是词组的简化编码)
encoder:                          # 定义编码生成的规则和排除模式
  exclude_patterns:               # ... 排除某些编码模式              
    - '^z.*$'                     # ... 排除所有以字母 `z` 开头的编码
  rules:                          # 定义了不同长度词组的〔编码生成规则〕
    - length_equal: 2             # ... 长度为 2 的词组使用公式 `AaAbBaBb` 生成编码
      formula: "AaAbBaBb"
    - length_equal: 3             # ... 长度为 3 的词组使用公式 `AaBaCaCb` 生成编码
      formula: "AaBaCaCb"
    - length_in_range: [4, 10]    # ... 长度为 3 的词组使用公式 `AaBaCaZa` 生成编码
      formula: "AaBaCaZa"

上述 YAML 配置文件定义了一个 五笔 86 输入法 的架构。

公式说明

公式中的字母代表编码的生成规则:

  • ABC 等表示从词组的第 1、2、3 个字中提取编码。
  • abc 等表示提取编码的特定部分(如首字母或特定位置的字母)。
  • Z 可能表示从整个词组中提取编码。

例如:

  • AaAbBaBb 表示:
    • 从第 1 个字提取编码的第 1 部分(A)和第 2 部分(a)。
    • 从第 2 个字提取编码的第 1 部分(B)和第 2 部分(b)。

这个配置文件定义了一个五笔 86 输入法的编码规则和数据结构,支持不同长度的词组编码生成,并通过权重排序优化用户体验。排除模式和编码公式的设计使得输入法更加灵活和高效。