pyim-5.3.3/0000755000175000017500000000000014476561521012345 5ustar dogslegdogslegpyim-5.3.3/pyim-cstring-utils.el0000644000175000017500000002642614362212573016456 0ustar dogslegdogsleg;;; pyim-cstring-utils.el --- Chinese string tools for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-cstring) (require 'pyim-dhashcache) (defgroup pyim-cstring nil "Chinese string tools for pyim." :group 'pyim) ;; ** 中文字符串分词相关功能 (defun pyim-cstring-split-to-list (chinese-string &optional max-word-length delete-dups prefer-short-word) "一个基于 pyim 的中文分词函数。这个函数可以将中文字符串 CHINESE-STRING 分词,得到一个词条 alist,这个 alist 的元素都是列 表,其中第一个元素为分词得到的词条,第二个元素为词条相对于字符串 中的起始位置,第三个元素为结束位置。分词时,默认词条不超过6个字符, 用户可以通过 MAX-WORD-LENGTH 来自定义,但值得注意的是:这个值设置 越大,分词速度越慢。 如果 DELETE-DUPS 设置为 non-nil, 一个中文字符串只保留一种分割方式。 比如: 我爱北京天安门 => 我爱 北京 天安门 如果 PREFER-SHORT-WORD 为 non-nil, 去重的时候则优先保留较短的词。 注意事项: 1. 这个工具使用暴力匹配模式来分词,*不能检测出* pyim 词库中不存在 的中文词条。 2. 这个函数的分词速度比较慢,仅仅适用于中文短句的分词,不适用于文 章分词。根据评估,20个汉字组成的字符串需要大约0.3s, 40个汉字 消耗1s,随着字符串长度的增大消耗的时间呈几何倍数增加。" ;; 如果 pyim 词库没有加载,加载 pyim 词库,确保 `pyim-dcache-get' 可以正常运行。 (pyim-dcache-init-variables) (let (result) (dolist (string-list (pyim-cstring--substrings chinese-string max-word-length)) (let ((pinyin-list (pyim-cstring-to-pinyin (car string-list) nil "-" t))) (dolist (pinyin pinyin-list) (let ((words (pyim-dcache-get pinyin '(code2word)))) ; 忽略个人词库可以提高速度 (dolist (word words) (when (equal word (car string-list)) (push string-list result))))))) (if delete-dups ;; 判断两个词条在字符串中的位置是否冲突,如果冲突,仅保留一个。 (cl-delete-duplicates result :test (lambda (x1 x2) (let ((begin1 (nth 1 x1)) (begin2 (nth 1 x2)) (end1 (nth 2 x1)) (end2 (nth 2 x2))) (not (or (<= end1 begin2) (<= end2 begin1))))) :from-end prefer-short-word) result))) (defun pyim-cstring-split-to-string (string &optional prefer-short-word separator max-word-length) "将中文字符串 STRING 分词. 在分词的位置插入空格或者自定义分隔符 SEPERATERS,默认情况下较长的 词条优先使用,如果 PREFER-SHORT-WORD 设置为 t,则优先使用较短的词 条。默认最长词条不超过6个字符,用户可以通 MAX-WORD-LENGTH 来自定 义词条的最大长度,但值得注意的是,这个值设置越大,分词速度越慢。" (mapconcat (lambda (str) (when (> (length str) 0) (if (not (pyim-string-match-p "\\CC" str)) (pyim-cstring--split-to-string str prefer-short-word separator max-word-length) str))) (pyim-pymap-split-string string) (or separator " "))) (defun pyim-cstring--split-to-string (chinese-string &optional prefer-short-word separator max-word-length) "`pyim-cstring-split-to-string' 内部函数。" (let ((str-length (length chinese-string)) (word-list (pyim-cstring-split-to-list chinese-string max-word-length t prefer-short-word)) position-list result) ;; 提取词条相对于字符串的位置信息。 (dolist (word word-list) (push (nth 1 word) position-list) (push (nth 2 word) position-list)) ;; 将位置信息由小到大排序。 (setq position-list (cl-delete-duplicates (sort position-list #'<))) ;; 在分词的位置插入空格或者用户指定的分隔符。 (dotimes (i str-length) (when (and (> i 0) (member i position-list)) (push (or separator " ") result)) (push (substring chinese-string i (1+ i)) result)) (setq result (nreverse result)) (string-join result))) (defun pyim-cstring-split-buffer () "将一个 buffer 中的中文文章,进行分词操作。" (interactive) (message "分词开始!") (goto-char (point-min)) (while (not (eobp)) (let ((string (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) (delete-region (line-beginning-position) (min (+ (line-end-position) 1) (point-max))) (insert (pyim-cstring-split-to-string string)) (insert "\n"))) (goto-char (point-min)) (message "分词完成!")) ;; ** 获取光标处中文词条的功能 (defun pyim-cstring-words-at-point (&optional end-of-point) "获取光标当前的词条列表,当 END-OF-POINT 设置为 t 时,获取光标后的 词条列表。词条列表的每一个元素都是列表,这些列表的第一个元素为词 条,第二个元素为光标处到词条头部的距离,第三个元素为光标处到词条 尾部的距离。 其工作原理是: 1. 使用 `thing-at-point' 获取当前光标处的一个字符串,一般而言:英 文会得到一个单词,中文会得到一个句子。 2. 英文单词直接返回这个单词的列表。 3. 中文句子首先用 `pyim-cstring-split-to-list' 分词,然后根据光标 在中文句子中的位置,筛选出符合要求的中文词条。得到并返回 *一个* 或者 *多个* 词条的列表。" ;; ;; 光标到词 光标到词 ;; 首的距离 尾的距离 ;; | | ;; 获取光标当前的词条列表 -> (("的词" 2 0) ("词条" 1 1)) ;; (let* ((case-fold-search t) (current-pos (point)) (current-char (if end-of-point (string (following-char)) (string (preceding-char)))) (str (thing-at-point 'word t)) (str-length (length str)) (str-boundary (bounds-of-thing-at-point 'word)) (str-beginning-pos (when str-boundary (car str-boundary))) (str-end-pos (when str-boundary (cdr str-boundary))) (str-offset (when (and str-beginning-pos str-end-pos) (if (= current-pos str-end-pos) (- str-end-pos str-beginning-pos) (- current-pos str-beginning-pos)))) str-offset-adjusted words-alist results) ;; 当字符串长度太长时, `pyim-cstring-split-to-list' ;; 的速度比较慢,这里确保待分词的字符串长度不超过10. (when (and str (not (pyim-string-match-p "\\CC" str))) (if (> str-offset 5) (progn (setq str-offset-adjusted 5) (setq str (substring str (- str-offset 5) (min (+ str-offset 5) str-length)))) (setq str-offset-adjusted str-offset) (setq str (substring str 0 (min 9 str-length))))) (cond (;; FIXME: 在光标在 buffer 开头或者行首时,直接返回 nil. ;; 也许这块应该更好的处理。 (or (bobp) (eq (point) (line-beginning-position))) nil) ((and str (not (pyim-string-match-p "\\CC" str))) (setq words-alist (pyim-cstring-split-to-list str)) (dolist (word-list words-alist) (let ((word-begin (nth 1 word-list)) (word-end (nth 2 word-list))) (if (if end-of-point (and (< str-offset-adjusted word-end) (>= str-offset-adjusted word-begin)) (and (<= str-offset-adjusted word-end) (> str-offset-adjusted word-begin))) (push (list (car word-list) (- str-offset-adjusted word-begin) ;; 例如: ("你好" 1 1) (- word-end str-offset-adjusted)) results)))) (or results (list (if end-of-point (list current-char 0 1) (list current-char 1 0))))) (str (list (list str (- current-pos str-beginning-pos) (- str-end-pos current-pos))))))) ;; ** 让 forward/backward 支持中文 (defun pyim-cstring-forward-word (&optional arg) "向前移动 ARG 英文或者中文词,向前移动时基于 *最长* 的词移动。" (interactive "P") (or arg (setq arg 1)) (dotimes (_ arg) (let* ((words (pyim-cstring-words-at-point t)) (max-length (cl-reduce #'max (cons 0 (mapcar (lambda (word) (nth 2 word)) words)))) (max-length (max (or max-length 1) 1))) (forward-char max-length)))) (defun pyim-cstring-backward-word (&optional arg) "向后移动 ARG 个英文或者中文词,向后移动时基于 *最长* 的词移动。" (interactive "P") (or arg (setq arg 1)) (dotimes (_ arg) (let* ((words (pyim-cstring-words-at-point)) (max-length (cl-reduce #'max (cons 0 (mapcar (lambda (word) (nth 1 word)) words)))) (max-length (max (or max-length 1) 1))) (backward-char max-length)))) (defalias 'pyim-cwords-at-point #'pyim-cstring-words-at-point) (defalias 'pyim-forward-word #'pyim-cstring-forward-word) (defalias 'pyim-backward-word #'pyim-cstring-backward-word) ;; * Footer (provide 'pyim-cstring-utils) ;;; pyim-cstring-utils.el ends here pyim-5.3.3/.elpaignore0000644000175000017500000000002114353263012014450 0ustar dogslegdogslegsnapshots .githubpyim-5.3.3/pyim-dict-manager.el0000644000175000017500000001771514402056612016176 0ustar dogslegdogsleg;;; pyim-dict-manager.el --- Dict manager for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-dict) (defgroup pyim-dict nil "Dict tools for pyim." :group 'pyim) (defvar pyim-dict-manager--buffer "*pyim-dict-manager*") (defun pyim-dict-manager-refresh () "Refresh the contents of the *pyim-dict-manager* buffer." (interactive) (with-current-buffer pyim-dict-manager--buffer (let ((inhibit-read-only t) (dicts-list pyim-dicts) (format-string "%-4s %-4s %-60s\n") (face-attr '((foreground-color . "DarkOrange2") (bold . t))) (i 1)) (erase-buffer) (insert (propertize (format format-string "序号" "启用" "词库文件") 'face face-attr)) (insert (propertize (format format-string "----" "----" "----------------------------------------------------------------------\n") 'face face-attr)) (if (not pyim-dicts) (insert "拼音词库是 pyim 使用顺手与否的关键。根据经验估计: 1. 当词库词条超过100万时 (词库文件>20M),pyim 选词频率大大降低。 2. 当词库词条超过100万时,pyim 中文输入体验可以达到搜狗输入法的 80%。 想快速体验 pyim 输入法的用户, 可以使用 pyim-basedict: (require 'pyim-basedict) (pyim-basedict-enable) 喜欢折腾的用户可以从下面几个途径获得 pyim 更详细的信息。 1. 使用 `C-h v pyim-dicts' 了解 pyim 词库文件格式。 2. 了解如何导入其它输入法的词库。 1. 使用 package 管理器查看 pyim 包的简介 2. 阅读 pyim.el 文件 Commentary 3. 查看 pyim 在线 README:https://github.com/tumashu/pyim\n") (dolist (dict dicts-list) (let ((disable (plist-get dict :disable)) (file (plist-get dict :file))) (insert (propertize (format format-string i (if disable "NO" "YES") file) 'id i 'disable disable 'file file))) (setq i (1+ i)))) (insert (propertize " 操作命令:[A] 添加词库 [D] 删除词库 [P] 向上移动 [N] 向下移动 [g] 刷新页面 [s] 保存配置 [R] 重启输入法 [C-c C-c] 禁用/启用当前词库" 'face face-attr))))) (defun pyim-dict-manager-toggle-dict (&optional _enable) "启用当前行对应的词库。" (interactive) (when (equal (buffer-name) pyim-dict-manager--buffer) (let* ((id (get-text-property (point) 'id)) (dict (cl-copy-list (nth (1- id) pyim-dicts))) (disable (plist-get dict :disable)) (line (line-number-at-pos))) (setf (nth (1- id) pyim-dicts) (plist-put dict :disable (not disable))) (if (not disable) (message "禁用当前词库") (message "启用当前词库")) (pyim-dict-manager-refresh) (goto-char (point-min)) (forward-line (- line 1))))) (defun pyim-dict-manager-delete-dict () "从 `pyim-dicts' 中删除当前行对应的词库信息。" (interactive) (when (equal (buffer-name) pyim-dict-manager--buffer) (let ((id (get-text-property (point) 'id)) (line (line-number-at-pos))) (when (yes-or-no-p "确定要删除这条词库信息吗? ") (setq pyim-dicts (delq (nth (1- id) pyim-dicts) pyim-dicts)) (pyim-dict-manager-refresh) (goto-char (point-min)) (forward-line (- line 1)))))) (defun pyim-dict-manager-dict-position-up () "向上移动词库。" (interactive) (when (equal (buffer-name) pyim-dict-manager--buffer) (let* ((id (get-text-property (point) 'id)) (dict1 (nth (- id 1) pyim-dicts)) (dict2 (nth (- id 2) pyim-dicts)) (line (line-number-at-pos))) (when (> id 1) (setf (nth (- id 1) pyim-dicts) dict2) (setf (nth (- id 2) pyim-dicts) dict1) (pyim-dict-manager-refresh) (goto-char (point-min)) (forward-line (- line 2)))))) (defun pyim-dict-manager-dict-position-down () "向下移动词库。" (interactive) (when (equal (buffer-name) pyim-dict-manager--buffer) (let* ((id (get-text-property (point) 'id)) (dict1 (nth (- id 1) pyim-dicts)) (dict2 (nth id pyim-dicts)) (length (length pyim-dicts)) (line (line-number-at-pos))) (when (< id length) (setf (nth (1- id) pyim-dicts) dict2) (setf (nth id pyim-dicts) dict1) (pyim-dict-manager-refresh) (goto-char (point-min)) (forward-line line))))) (defun pyim-dict-manager-save-dict-info () "使用 `customize-save-variable' 函数将 `pyim-dicts' 保存到 '~/.emacs' 文件中。" (interactive) ;; 将`pyim-dict'的设置保存到emacs配置文件中。 (customize-save-variable 'pyim-dicts pyim-dicts) (message "将 pyim 词库配置信息保存到 ~/.emacs 文件。")) (defun pyim-dict-manager-add-dict () "为 `pyim-dicts' 添加词库信息。" (interactive) (when (equal (buffer-name) pyim-dict-manager--buffer) (let ((line (line-number-at-pos)) dict name file first-used) (setq name (read-from-minibuffer "请输入词库名称: ")) (setq file (read-file-name "请选择词库文件: " "~/")) (setq first-used (yes-or-no-p "是否让 pyim 优先使用词库? ")) (setq dict `(:name ,name :file ,file)) (if first-used (add-to-list 'pyim-dicts dict) (add-to-list 'pyim-dicts dict t)) (pyim-dict-manager-refresh) (goto-char (point-min)) (forward-line (- line 1))))) (declare-function pyim-restart "pyim") (define-derived-mode pyim-dict-manager-mode special-mode "pyim-dicts-manager" "Major mode for managing pyim dicts" (read-only-mode) (define-key pyim-dict-manager-mode-map (kbd "D") #'pyim-dict-manager-delete-dict) (define-key pyim-dict-manager-mode-map (kbd "g") #'pyim-dict-manager-refresh) (define-key pyim-dict-manager-mode-map (kbd "A") #'pyim-dict-manager-add-dict) (define-key pyim-dict-manager-mode-map (kbd "N") #'pyim-dict-manager-dict-position-down) (define-key pyim-dict-manager-mode-map (kbd "P") #'pyim-dict-manager-dict-position-up) (define-key pyim-dict-manager-mode-map (kbd "s") #'pyim-dict-manager-save-dict-info) (define-key pyim-dict-manager-mode-map (kbd "C-c C-c") #'pyim-dict-manager-toggle-dict) (define-key pyim-dict-manager-mode-map (kbd "R") #'pyim-restart)) ;;;###autoload (defun pyim-dicts-manager () "pyim 词库管理器。 使用这个词库管理器可以方便的执行下列命令: 1. 添加词库。 2. 删除词库。 3. 向上和向下移动词库。 4. 保存词库设置。 5. 重启输入法。" (interactive) (let ((buffer (get-buffer-create pyim-dict-manager--buffer))) (pyim-dict-manager-refresh) (switch-to-buffer buffer) (pyim-dict-manager-mode) (setq truncate-lines t))) ;; * Footer (provide 'pyim-dict-manager) ;;; pyim-dict-manager.el ends here pyim-5.3.3/README-elpa0000644000175000017500000010611414476561521014147 0ustar dogslegdogsleg ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ PYIM 是一个 EMACS 中文输入法,支持全拼,双拼,五 笔,仓颉 和 RIME 等 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1 不兼容更新 ════════════ 1.1 <2022-06-15 Wed> Do not require popup in pyim-page.el ────────────────────────────────────────────────────────── popup 是一个非 gnu elpa 包,pyim-page.el 不应该 require 它,需要用户自 己手动require, 使用 popup tooltip 的用户需要在配置中添加: ┌──── │ (require 'popup) └──── 1.2 <2022-06-13 Mon> pyim-dcache-backend 所需的 package 需要用户手工加载了。 ───────────────────────────────────────────────────────────────────────────── 以前 pyim 可以根据 pyim-dcache-backend 的取值自动加载需要的 package, 这样做虽然方便,但代码特别容易出现问题,考虑到 pyim 未来支持的后端不会 有太大变化,我删除了这个功能,为了向后兼容,pyim 目前会自动加载 pyim-dregcache 包, 但这个兼容代码未来可能会删除,所以使用 pyim-dregcache 的用户,建议给自己的配置中添加: ┌──── │ (require 'pyim-dregcache) └──── 1.3 <2022-05-29 Sun> pyim-cregexp-utils, pyim-cstring-utils 和 pyim-dict-manager 需要用户手动 require. ─────────────────────────────────────────────────────────────────────────────────────────────────────── 为降低 pyim 代码的复杂度,减少 pyim 依赖包的数量,下面三个包不会自动加 载,需要用户手动 require. 1. pyim-cregexp-utils 2. pyim-cstring-utils 3. pyim-dict-manager (使用 elpa 安装词库,或者手动管理 pyim-dicts 变量 的用户不需要这个包) 1.4 <2021-04-28 Wed> 五笔输入法和仓颉输入法的不兼容更新 ──────────────────────────────────────────────────────── 五笔输入法和仓颉输入法原来使用一个标点符号作为 code-prefix, 现在使用 "wubi/" 和"cangjie/" 这种形式的 code-prefix, 这样可以减少不同输入法误 用同一个 code-prefix带来的词库冲突。 五笔输入法的 scheme 设置已经移到 pyim-wbdict 包,仓颉输入法的 scheme 设置已经移到 pyim-cangjie5dict 包。 使用上述两个包的用户,此次变更不受影响,因为两个包使用新的 code-prefix. 受影响的是自己维护五笔和仓颉词库用户,这些用户需要做以下更新: 1. 五笔用户 1. 需要 (require 'pyim-wbdict), 加载五笔 scheme 设置。 2. 需要将自己的五笔词库文件中的 code-prefix "." 替换为 "wubi/". 3. 运行 `pyim-upgrade' 命令,升级 icode2word 词库缓存。 2. 仓颉用户 1. 需要 (require 'pyim-cangjie5dict), 加载仓颉 scheme 设置。 2. 需要将自己的五笔词库文件中的 code-prefix "@" 替换为 "cangjie/". 2 截图 ══════ 3 简介 ══════ pyim 是 Emacs 环境下的一个中文输入法,最初这个输入法只支持全拼输入,后 来根据同学的提议,添加了五笔等输入法的支持,“pyim” 现在可以理解为: (Peng You input method) 4 背景 ══════ pyim 源于 Emacs-eim。 Emacs-eim 是 Emacs 环境下的一个中文输入法框架, 支持拼音,五笔,仓颉, 二笔等多种输入法,但遗憾的是,2008 年之后它就停止了开发。 虽然外部输入法功能强大,但不能和 Emacs 默契的配合,这一点极大的损害了 Emacs 那种*行云流水* 的感觉。而本人在使用 Emacs-eim 的过程中发现: 1. *当 Emacs-eim 词库词条很大时,选词频率大大降低,中文体验增强。* 2. *随着使用时间的延长,Emacs-eim 会越来越好用(个人词库的积累)。* 于是我 fork 了 Emacs-eim 输入法的部分代码, 创建了新项目:pyim。 5 目标 ══════ pyim 的目标是: *尽最大的努力成为一个好用的 Emacs 中文输入法* ,具体可 表现为三个方面: 1. Fallback: 当外部输入法不能使用时,比如在 console 或者 cygwin 环境下, 尽最大可能让 Emacs 用户不必为输入中文而烦恼。 2. Integration: 尽最大可能减少输入法切换频率,让中文输入不影响 Emacs 的体验。 3. Exchange: 尽最大可能简化 pyim 使用其他优秀输入法的词库的难度和复杂 度。 6 特点 ══════ 1. pyim 支持全拼,双拼,五笔和仓颉等输入法,其中对全拼的支持最好。 2. pyim 通过添加词库的方式优化输入法。 3. pyim 使用文本词库格式,方便处理。 4. pyim 可以作为 rime 的前端使用。 7 安装 ══════ 1. M-x package-install RET pyim RET 2. 在 Emacs 配置文件中(比如: ~/.emacs)添加如下代码: ┌──── │ (require 'pyim) │ (require 'pyim-basedict) ; 拼音词库设置,五笔用户 *不需要* 此行设置 │ (pyim-basedict-enable) ; 拼音词库,五笔用户 *不需要* 此行设置 │ (setq default-input-method "pyim") └──── 8 配置 ══════ 8.1 配置实例 ──────────── 对 pyim 感兴趣的同学,可以看看本人的 pyim 配置,但要注意不要乱抄探针配 置。 ┌──── │ (require 'pyim) │ (require 'pyim-basedict) │ (require 'pyim-cregexp-utils) │ │ ;; 如果使用 popup page tooltip, 就需要加载 popup 包。 │ ;; (require 'popup nil t) │ ;; (setq pyim-page-tooltip 'popup) │ │ ;; 如果使用 pyim-dregcache dcache 后端,就需要加载 pyim-dregcache 包。 │ ;; (require 'pyim-dregcache) │ ;; (setq pyim-dcache-backend 'pyim-dregcache) │ │ ;; 加载 basedict 拼音词库。 │ (pyim-basedict-enable) │ │ ;; 将 Emacs 默认输入法设置为 pyim. │ (setq default-input-method "pyim") │ │ ;; 显示 5 个候选词。 │ (setq pyim-page-length 5) │ │ ;; 金手指设置,可以将光标处的编码(比如:拼音字符串)转换为中文。 │ (global-set-key (kbd "M-j") 'pyim-convert-string-at-point) │ │ ;; 按 "C-" 将光标前的 regexp 转换为可以搜索中文的 regexp. │ (define-key minibuffer-local-map (kbd "C-") 'pyim-cregexp-convert-at-point) │ │ ;; 设置 pyim 默认使用的输入法策略,我使用全拼。 │ (pyim-default-scheme 'quanpin) │ ;; (pyim-default-scheme 'wubi) │ ;; (pyim-default-scheme 'cangjie) │ │ ;; 设置 pyim 是否使用云拼音 │ ;; (setq pyim-cloudim 'baidu) │ │ ;; 设置 pyim 探针 │ ;; 设置 pyim 探针设置,这是 pyim 高级功能设置,可以实现 *无痛* 中英文切换 :-) │ ;; 我自己使用的中英文动态切换规则是: │ ;; 1. 光标只有在注释里面时,才可以输入中文。 │ ;; 2. 光标前是汉字字符时,才能输入中文。 │ ;; 3. 使用 M-j 快捷键,强制将光标前的拼音字符串转换为中文。 │ ;; (setq-default pyim-english-input-switch-functions │ ;; '(pyim-probe-dynamic-english │ ;; pyim-probe-isearch-mode │ ;; pyim-probe-program-mode │ ;; pyim-probe-org-structure-template)) │ │ ;; (setq-default pyim-punctuation-half-width-functions │ ;; '(pyim-probe-punctuation-line-beginning │ ;; pyim-probe-punctuation-after-punctuation)) │ │ ;; 开启代码搜索中文功能(比如拼音,五笔码等) │ (pyim-isearch-mode 1) └──── 8.2 添加词库文件 ──────────────── pyim 默认使用 pyim-basedict 词库, 这个词库的词条量8万左右,是一个 *非 常小* 的拼音词库,源于:libpinyin 项目 如果 pyim-basedict 不能满足需求,用户可以使用其他方式为 pyim 添加拼音 词库,具体方式请参考 小结。 8.3 激活 pyim ───────────── ┌──── │ (setq default-input-method "pyim") │ (global-set-key (kbd "C-\\") 'toggle-input-method) └──── 9 使用 ══════ 9.1 常用快捷键 ────────────── ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 输入法快捷键 功能 ─────────────────────────────────────────────────── C-n 或 M-n 或 + 或 . 向下翻页 C-p 或 M-p 或 - 或 , 向上翻页 C-f 选择下一个备选词 C-b 选择上一个备选词 SPC 确定输入 RET 或 C-m 字母上屏 C-c 取消输入 C-g 取消输入并保留已输入的中文 TAB 模糊音调整 DEL 或 BACKSPACE 删除最后一个字符 C-DEL 或 C-BACKSPACE 删除最后一个拼音 M-DEL 或 M-BACKSPACE 删除最后一个拼音 F1,F2,F3,F4 以词定字 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 9.2 使用云输入法 ──────────────── pyim 可以使用搜索引擎提供的云输入法服务,比如: ┌──── │ (setq pyim-cloudim 'baidu) │ ;; (setq pyim-cloudim 'google) └──── 9.3 使用双拼模式 ──────────────── pyim 支持双拼输入模式,用户可以通过变量 `pyim-default-scheme' 来设定: ┌──── │ (pyim-default-scheme 'pyim-shuangpin) └──── 注意: 1. pyim 支持微软双拼(microsoft-shuangpin)和小鹤双拼 (xiaohe-shuangpin)。 2. 用户可以使用函数 `pyim-scheme-add' 添加自定义双拼方案。 3. 用户可能需要重新设置 `pyim-outcome-trigger'。 9.4 使用 rime 输入法 ──────────────────── 具体安装和使用方式请查看 pyim-liberime 包的 Commentary 部分。 9.5 使用型码输入法 ────────────────── 1. 五笔输入法可以参考: 2. 仓颉输入法可以参考: 3. 三码郑码(至至郑码)输入法可以参考: 如果用户在使用型码输入法的过程中,忘记了某个字的编码,可以按 TAB 键临 时切换到辅助输入法来输入,辅助输入法可以通过 `pyim-assistant-scheme' 来设置。 9.6 让选词框跟随光标 ──────────────────── 用户可以通过下面的设置让 pyim 在 *光标处* 显示一个选词框: 1. 使用 popup 或者 popon 包来绘制选词框 (emacs overlay 机制) ┌──── │ (require 'popup) │ (setq pyim-page-tooltip 'popup) └──── ┌──── │ (require 'popon) │ (setq pyim-page-tooltip 'popon) └──── 2. 使用 posframe 来绘制选词框 ┌──── │ (require 'posframe) │ (setq pyim-page-tooltip 'posframe) └──── 注意:pyim 不会自动安装 posframe, 用户需要手动安装这个包, 3. 按照优先顺序自动选择一个可用的 tooltip ┌──── │ (setq pyim-page-tooltip '(posframe popup minibuffer)) └──── 9.7 调整 tooltip 选词框的显示样式 ───────────────────────────────── pyim 的选词框默认使用 *双行显示* 的样式,在一些特殊的情况下(比如: popup 显示的菜单错位),用户可以使用 *单行显示*的样式: ┌──── │ (setq pyim-page-style 'one-line) └──── 9.8 设置模糊音 ────────────── 可以通过设置 `pyim-pinyin-fuzzy-alist' 变量来自定义模糊音。 9.9 使用魔术转换器 ────────────────── 用户可以将待选词 “特殊处理” 后再 “上屏”,比如 “简体转繁体” 或者 “输入 中文,上屏英文” 之类的。 用户需要设置 `pyim-outcome-magic-converter', 比如:下面这个例子实现, 输入 “二呆”,“一个超级帅的小伙子” 上屏 :-) ┌──── │ (defun my-converter (string) │ (if (equal string "二呆") │ "“一个超级帅的小伙子”" │ string)) │ (setq pyim-outcome-magic-converter #'my-converter) └──── 9.10 切换全角标点与半角标点 ─────────────────────────── 1. 第一种方法:使用命令 `pyim-punctuation-toggle',全局切换。这个命令 主要用来设置变量: `pyim-punctuation-translate-p', 用户也可以手动设 置这个变量, 比如: ┌──── │ (setq-default pyim-punctuation-translate-p '(yes)) ;使用全角标点。 │ (setq-default pyim-punctuation-translate-p '(no)) ;使用半角标点。 │ (setq-default pyim-punctuation-translate-p '(auto)) ;中文使用全角标点,英文使用半角标点。 └──── 2. 第二种方法:使用命令 `pyim-punctuation-translate-at-point' 只切换光 标处标点的样式。 3. 第三种方法:设置变量 `pyim-outcome-trigger' ,输入变量设定的字符会 切换光标处标点的样式。 9.11 手动加词和删词 ─────────────────── 1. `pyim-convert-string-at-point' 金手指命令,可以比较方便的添加和删除 词条,比如: 1. 在 "你好" 后面输入2, 然后运行金手指命令,可以将 “你好” 加入个人 词库。 2. 在 “你好” 后面输入2-, 然后运行金手指命令,可以将 “你好” 从个人词 库删除。 3. 如果用户选择了一个词条,则运行金手指命令可以将选择的词条加入个人 词库。 2. `pyim-create-Ncchar-word-at-point' 这是一组命令,从光标前提取N个汉 字字符组成字符串,并将其加入个人词库。 3. `pyim-outcome-trigger' 以默认设置为例:在 “我爱吃红烧肉” 后输入 “5v”,可以将“爱吃红烧肉”这个词条保存到用户个人词库。 4. `pyim-create-word-from-selection', 选择一个词条,运行这个命令后,就 可以将这个词条添加到个人词库。 5. `pyim-delete-word' 从个人词库中删除当前高亮选择的词条。 9.12 pyim 输入状态指示器 ──────────────────────── pyim 输入状态指示器可以帮助用户快速了解当前 pyim 是处于英文输入状态还 是中文输入状态,因为 pyim probe 探针功能可以让中英文输入状态动态切换, 所以快速了解当前中英文输入状态有时候显得很重要。 pyim 当前内置两种指示器实现方式: 1. 改变光标颜色: pyim-indicator-with-cursor-color, 用户可以使用变量 pyim-indicator-cursor-color 来配置两种输入状态对应的光标颜色。 2. 使用 modeline 显示状态字符串:pyim-indicator-with-mode-line, 用户可 以使用变量pyim-indicator-modeline-string 来配置两种状态对应的显示字 符串。 设置默认启用的指示器有两个,用户可以使用下面的变量调整: ┌──── │ (setq pyim-indicator-list (list #'pyim-indicator-with-cursor-color #'pyim-indicator-with-modeline)) └──── 注意事项: 1. 用户切换 emacs 主题之后,最好重启 pyim 一下。 2. pyim-indicator-with-cursor-color 这个 indicator 很容易和其它设置 cursor 颜色的包冲突,因为都调用 set-cursor-color,遇到这种情况后, 用户需要自己解决冲突,pyim-indicator 提供了一个简单的机制: ┌──── │ (setq pyim-indicator-list (list #'my-pyim-indicator-with-cursor-color #'pyim-indicator-with-modeline)) │ │ (defun my-pyim-indicator-with-cursor-color (input-method chinese-input-p) │ (if (not (equal input-method "pyim")) │ (progn │ ;; 用户在这里定义 pyim 未激活时的光标颜色设置语句 │ (set-cursor-color "red")) │ (if chinese-input-p │ (progn │ ;; 用户在这里定义 pyim 输入中文时的光标颜色设置语句 │ (set-cursor-color "green")) │ ;; 用户在这里定义 pyim 输入英文时的光标颜色设置语句 │ (set-cursor-color "blue")))) └──── 9.13 pyim 高级功能 ────────────────── 1. 根据环境自动切换到英文输入模式,使用 pyim-english-input-switch-functions 配置。 2. 根据环境自动切换到半角标点输入模式,使用 pyim-punctuation-half-width-functions 配置。 3. 如果想在某种环境下强制输入中文,可以使用 pyim-force-input-chinese-functions来配置,这个设置可以屏蔽掉 pyim-english-input-switch-functions 的设置。 注意:上述两个功能使用不同的变量设置, *千万不要搞错* 。 9.13.1 根据环境自动切换到英文输入模式 ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 探针函数 功能说明 ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── pyim-probe-program-mode 如果当前的 mode 衍生自 prog-mode,那么仅仅在字符串和 comment 中开启中文输入模式 ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── pyim-probe-org-speed-commands 解决 org-speed-commands 与 pyim 冲突问题 pyim-probe-isearch-mode 使用 isearch 搜索时,强制开启英文输入模式 注意:想要使用这个功能,pyim-isearch-mode 必须激活 ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── pyim-probe-org-structure-template 使用 org-structure-template 时,关闭中文输入模式 ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 1. 当前字符为中文字符时,输入下一个字符时默认开启中文输入 pyim-probe-dynamic-english 2. 当前字符为其他字符时,输入下一个字符时默认开启英文输入 3. 使用命令 pyim-convert-string-at-point 可以将光标前的拼音字符串强制转换为中文。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 激活方式: ┌──── │ (setq-default pyim-english-input-switch-functions │ '(probe-function1 probe-function2 probe-function3)) └──── 注意事项: 1. 上述函数列表中,任意一个函数的返回值为 t 时,pyim 切换到英文输入模 式。 2. [Emacs-rime] 和 [smart-input-source] 也有类似探针的功能,其对应函数 可以直接或者简单包装后作为 pyim 探针使用,有兴趣的同学可以了解一下。 [Emacs-rime] [smart-input-source] 9.13.2 根据环境自动切换到半角标点输入模式 ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 探针函数 功能说明 ────────────────────────────────────────────────────────────────────── pyim-probe-punctuation-line-beginning 行首强制输入半角标点 ────────────────────────────────────────────────────────────────────── pyim-probe-punctuation-after-punctuation 半角标点后强制输入半角标点 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 激活方式: ┌──── │ (setq-default pyim-punctuation-half-width-functions │ '(probe-function4 probe-function5 probe-function6)) └──── 注:上述函数列表中,任意一个函数的返回值为 t 时,pyim 切换到半角标点输 入模式。 10 开发 ═══════ 请参考 [Development.org] 文档 [Development.org] 11 试用 ═══════ 在pyim项目根目录运行shell命令 `make runemacs' 试用最新的pyim。 只有pyim和其依赖的包被载入。用户自己的emacs配置不会被载入。 指定运行的Emacs版本用以下命令, ┌──── │ EMACS=~/my-whatever-directory/bin/emacs make runemacs └──── Emacs启动后 "M-x toggle-input-method" 或按 "C-\\" 打开输入法。 12 Tips ═══════ 12.1 pyim 有时候会出现卡顿,如何处理。 ────────────────────────────────────── 可以将云搜词和当前 buffer 搜词功能关闭试试看。 ┌──── │ (setq pyim-cloudim nil) │ (setq pyim-candidates-search-buffer-p nil) └──── 12.2 如何快速切换 scheme ──────────────────────── 可以试试 pyim-default-scheme 命令。 12.3 关闭输入联想词功能 (默认开启) ────────────────────────────────── ┌──── │ (setq pyim-enable-shortcode nil) └──── 12.4 形码输入法如何微调候选词序 ─────────────────────────────── ┌──── │ (setq pyim-candidates-xingma-words-function #'my-func) └──── 12.5 如何将个人词条相关信息导入和导出? ─────────────────────────────────────── 1. 导入使用命令: pyim-dcache-import 2. 导出使用命令: pyim-dcache-export 12.6 pyim 出现错误时,如何开启 debug 模式 ───────────────────────────────────────── ┌──── │ (setq debug-on-error t) └──── 12.7 将光标处的拼音或者五笔字符串转换为中文 (与 vimim 的 “点石成金” 功能类似) ───────────────────────────────────────────────────────────────────────────── ┌──── │ (global-set-key (kbd "M-i") 'pyim-convert-string-at-point) └──── 12.8 如何使用其它字符翻页 ───────────────────────── ┌──── │ (define-key pyim-mode-map "." 'pyim-page-next-page) │ (define-key pyim-mode-map "," 'pyim-page-previous-page) └──── 12.9 如何用 ";" 来选择第二个候选词 ────────────────────────────────── ┌──── │ (define-key pyim-mode-map ";" │ (lambda () │ (interactive) │ (pyim-select-word-by-number 2))) └──── 12.10 如何添加自定义拼音词库 ──────────────────────────── pyim 默认没有携带任何拼音词库,用户可以使用下面几种方式,获取质量较好 的拼音词库: 12.10.1 第一种方式 (Windows 用户推荐使用) ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ 使用词库转换工具将其他输入法的词库转化为 pyim 使用的词库:这里只介绍 windows 平台下的一个词库转换软件: 1. 软件名称: imewlconverter 2. 中文名称: 深蓝词库转换 3. 下载地址: 4. 依赖平台: Microsoft .NET Framework (>= 3.5) 使用方式: 如果生成的词库词频不合理,可以按照下面的方式处理(非常有用的功能): 生成词库后, ┌──── │ (require 'pyim-dict-manager) └──── 然后运行 `pyim-dicts-manager' ,按照命令提示,将转换得到的词库文件的信 息添加到`pyim-dicts' 中,完成后运行命令 `pyim-restart' 或者重启emacs。 12.10.2 第二种方式 (Linux & Unix 用户推荐使用) ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ E-Neo 同学编写了一个词库转换工具: [scel2pyim] , 可以将一个搜狗词库转换 为 pyim 词库。 1. 软件名称: scel2pyim 2. 下载地址: 3. 编写语言: C语言 [scel2pyim] 12.10.3 第三种方式 ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ 可以了解: 12.11 如何手动安装和管理词库 ──────────────────────────── 这里假设有两个词库文件: 1. /path/to/pyim-dict1.pyim 2. /path/to/pyim-dict2.pyim 在 ~/.emacs 文件中添加如下一行配置。 ┌──── │ (setq pyim-dicts │ '((:name "dict1" :file "/path/to/pyim-dict1.pyim") │ (:name "dict2" :file "/path/to/pyim-dict2.pyim"))) └──── 注意事项: 1. 只有 :file 是 *必须* 设置的。 2. 必须使用词库文件的绝对路径。 3. 词库文件的编码必须为 utf-8-unix,否则会出现乱码。 12.12 Emacs 启动时加载 pyim 词库 ──────────────────────────────── ┌──── │ (add-hook 'emacs-startup-hook │ (lambda () (pyim-restart-1 t))) └──── 12.13 将汉字字符串转换为拼音字符串 ────────────────────────────────── 下面两个函数可以将中文字符串转换的拼音字符串或者列表,用于 emacs-lisp 编程。 1. `pyim-cstring-to-pinyin' (尽可能处理多音字,但有可能得到多个拼音) 2. `pyim-cstring-to-pinyin-simple' (尽可能处理多音字,但是只从可能的 拼音中获取第一个拼音) 12.14 中文分词 ────────────── pyim-cstring-utils 包含了一个简单的分词函数: `pyim-cstring-split-to-list', 可以将一个中文字符串分成一个词条列表,比 如: ┌──── │ (require 'pyim-cstring-utils) │ (pyim-cstring-split-to-list "我爱北京天安门") └──── 其中,每一个词条列表中包含三个元素,第一个元素为词条本身,第二个元素为 词条相对于字符串的起始位置,第三个元素为词条结束位置。 另一个分词函数是 `pyim-cstring-split-to-string', 这个函数将生成一个新 的字符串,在这个字符串中,词语之间用空格或者用户自定义的分隔符隔开。 注意,上述两个分词函数使用暴力匹配模式来分词,所以,*不能检测出* pyim 词库中不存在的中文词条。 12.15 获取光标处的中文词条 ────────────────────────── pyim-cstring-utils 包含了一个简单的命令: `pyim-cstring-words-at-point', 这个命令可以得到光标处的 *英文* 或者 * 中文* 词条的 *列表*,这个命令依赖分词函数: `pyim-cstring-split-to-list'。 12.16 让 `forward-word' 和 `back-backward’ 在中文环境下正常工作 ─────────────────────────────────────────────────────────────── 中文词语没有强制用空格分词,所以 Emacs 内置的命令 `forward-word' 和 `backward-word' 在中文环境不能按用户预期的样子执行,而是 forward/backward “句子”,pyim自带的两个命令可以在中文环境下正常工作: 1. `pyim-forward-word 2. `pyim-backward-word 用户只需将其绑定到快捷键上就可以了,比如: ┌──── │ (require 'pyim-cstring-utils) │ (global-set-key (kbd "M-f") 'pyim-forward-word) │ (global-set-key (kbd "M-b") 'pyim-backward-word) └──── 12.17 为 isearch 相关命令添加拼音搜索支持 ───────────────────────────────────────── pyim 安装后,可以通过下面的设置开启拼音搜索功能: ┌──── │ (require 'pyim-cregexp-utils) │ (pyim-isearch-mode 1) └──── 注意:这个功能有一些限制,搜索字符串中只能出现 “a-z” 和 “'”,如果有其 他字符(比如 regexp 操作符),则自动关闭拼音搜索功能。 开启这个功能后,一些 isearch 扩展有可能失效,如果遇到这种问题,只能禁 用这个 Minor-mode,然后联系 pyim 的维护者,看有没有法子实现兼容。 用户激活这个 mode 后,可以使用下面的方式 *强制关闭* isearch 搜索框中文 输入(即使在 pyim 激活的时候)。 ┌──── │ (setq-default pyim-english-input-switch-functions │ '(pyim-probe-isearch-mode)) └──── 12.18 创建一个搜索中文的 regexp ─────────────────────────────── ┌──── │ (pyim-cregexp-build ".*nihao.*") └──── 12.19 让 ivy 支持拼音搜索候选项功能 ─────────────────────────────────── ┌──── │ (require 'pyim-cregexp-utils) │ (setq ivy-re-builders-alist │ '((t . pyim-cregexp-ivy))) └──── 12.20 让 avy 支持拼音搜索 ───────────────────────── ┌──── │ (with-eval-after-load 'avy │ (defun my-avy--regex-candidates (fun regex &optional beg end pred group) │ (let ((regex (pyim-cregexp-build regex))) │ (funcall fun regex beg end pred group))) │ (advice-add 'avy--regex-candidates :around #'my-avy--regex-candidates)) └──── 12.21 让 vertico, selectrum 等补全框架,通过 orderless 支持拼音搜索候选项功能。 ─────────────────────────────────────────────────────────────────────────────── ┌──── │ (defun my-orderless-regexp (orig-func component) │ (let ((result (funcall orig-func component))) │ (pyim-cregexp-build result))) │ │ (advice-add 'orderless-regexp :around #'my-orderless-regexp) └──── pyim-5.3.3/pyim-scheme.el0000644000175000017500000003445514412763714015120 0ustar dogslegdogsleg;;; pyim-scheme.el --- scheme tools for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-common) (defgroup pyim-scheme nil "Scheme tools for pyim." :group 'pyim) (define-widget 'pyim-scheme 'lazy "输入法方案" :type '(choice (const :tag "全拼" quanpin) (const :tag "双拼" shuangpin) (const :tag "形码" xingma) (const :tag "五笔" wubi) (symbol :tag "其他"))) (defcustom pyim-default-scheme 'quanpin "设置 pyim 使用哪一种输入法方案,默认使用全拼输入." :type 'pyim-scheme) (defcustom pyim-assistant-scheme 'quanpin "设置辅助输入法方案. 这个功能主要用于五笔等形码输入法,在忘记编码的情况下, 临时激活某种辅助输入法(比如:拼音输入法)来输入汉字。" :type 'pyim-scheme) (defvar pyim-scheme--enable-assistant-p nil "设置临时 scheme, 用于五笔等形码输入法临时拼音输入。") (pyim-register-local-variables '(pyim-scheme--enable-assistant-p)) (defvar pyim-scheme--all-schemes nil "Pyim 支持的所有拼音方案.") (cl-defstruct (pyim-scheme (:constructor pyim-scheme-create) (:copier nil)) "输入法通用方案类型." (name nil :type symbol :documentation "输入法名称。") (document nil :type string :documentation "输入法简要说明。") (first-chars nil :type string :documentation "输入法启动后,可以处理的第一个字符。") (rest-chars nil :type string :documentation "输入法处理一个字符后,可以继续处理的字符。") (code-prefix nil :type string :documentation "pyim 词库用到的编码前缀,比如:wubi/ 等。") (code-prefix-history nil :type list :documentation "输入法以前使用过的编码前缀,用于编写词库升级程序。") (prefer-triggers nil :type list :documentation "单字符快捷键设置,有些输入法不使用某个字母,这个字母就可以做为快捷键使用。") (cregexp-support-p nil :type boolean :documentation "输入法是否支持从代码生成搜索中文的正则表达式。")) (cl-defstruct (pyim-scheme-quanpin (:include pyim-scheme) (:constructor pyim-scheme-quanpin-create) (:copier nil)) "全拼输入法方案类型。") (cl-defstruct (pyim-scheme-shuangpin (:include pyim-scheme-quanpin) (:constructor pyim-scheme-shuangpin-create) (:copier nil)) "双拼输入法方案类型。 在 PYIM 中,双拼输入法是建立在全拼输入法的基础上的,所以将其定义 为全拼输入法类型的子类型。" (keymaps nil :type list :documentation "双拼到全拼的声母韵母映射表。")) (cl-defstruct (pyim-scheme-xingma (:include pyim-scheme) (:constructor pyim-scheme-xingma-create) (:copier nil)) "形码输入法方案类型。 这个输入法方案类型代表那些重码少,编码长度固定的一类输入法,比如: 五笔输入法,仓颉输入法等。" (code-split-length nil :type number :documentation "代码分割长度。") (code-maximum-length nil :type number :documentation "代码最大长度。")) (cl-defstruct (pyim-scheme-wubi (:include pyim-scheme-xingma) (:constructor pyim-scheme-wubi-create) (:copier nil)) "五笔输入法方案类型。 单独创建五笔方案类型,是为了支持五笔反查功能,因为1到4字的中文词 语, 五笔编码有固定的规则,其它形码没有类似特点。" ) ;;;###autoload (defun pyim-default-scheme (&optional scheme-name) (interactive) (let* ((scheme-names (mapcar #'pyim-scheme-name pyim-scheme--all-schemes)) (scheme-name (or scheme-name (intern (completing-read "PYIM: 将 pyim-default-scheme 设置为:" scheme-names))))) (if (memq scheme-name scheme-names) (progn (setq pyim-default-scheme scheme-name) (message "PYIM: `pyim-default-scheme' 已经设置为 %s." scheme-name) scheme-name) (message "PYIM: %s 不是一个有效的 scheme 名称, 继续使用 %s." scheme-name pyim-default-scheme) nil))) (defun pyim-scheme-add (scheme-config) "Add SCHEME to `pyim-scheme--all-schemes'." (if (listp scheme-config) (let* ((scheme-name (car scheme-config)) (scheme-type (plist-get (cdr scheme-config) :class)) ;; `pyim-scheme-add' 在 pyim 使用 `cl-defstruct' 重构之前就已经存在 ;; 很长时间,使用下面的方式向后兼容。 (func (intern (format "pyim-scheme-%s-create" scheme-type))) ;; 函数 pyim-scheme-*-create 不识别 :class 参数,所以后续需要从 ;; scheme-config 中删除 :class xxx. (args (remove :class (plist-put (cdr scheme-config) :class :class))) (scheme (apply func :name scheme-name args)) schemes update-p) (when (and (symbolp scheme-name) (functionp func)) (dolist (x pyim-scheme--all-schemes) (push (if (equal (pyim-scheme-name x) scheme-name) (progn (setq update-p t) scheme) x) schemes)) (unless update-p (push scheme schemes)) (setq pyim-scheme--all-schemes (reverse schemes)))) (message "PYIM: Invalid pyim scheme config!"))) (defun pyim-scheme-current () "获取当前正在使用的 scheme。" (or (pyim-scheme-get (if pyim-scheme--enable-assistant-p pyim-assistant-scheme pyim-default-scheme)) (pyim-scheme-get 'quanpin))) (defun pyim-scheme-get (scheme-name) "获取名称为 SCHEME-NAME 的 scheme." (when scheme-name (cl-find-if (lambda (x) (equal (pyim-scheme-name x) scheme-name)) (pyim-scheme-get-all-schemes)))) (defun pyim-scheme-get-all-schemes () pyim-scheme--all-schemes) (defun pyim-scheme-assistant-enable-p () pyim-scheme--enable-assistant-p) (defun pyim-scheme-enable-assistant () (setq pyim-scheme--enable-assistant-p t)) (defun pyim-scheme-disable-assistant () (setq pyim-scheme--enable-assistant-p nil)) (defun pyim-scheme-toggle-assistant () (setq pyim-scheme--enable-assistant-p (not pyim-scheme--enable-assistant-p))) ;; 注意:这个 quanpin scheme 在 pyim 中有特殊的作用,许多功能都依赖 quanpin ;; scheme 的存在,所以这个 scheme 不可以删除,也不可以更改名字。 (pyim-scheme-add '(quanpin :document "全拼输入法方案(不可删除)。" :class quanpin :first-chars "abcdefghijklmnopqrstuwxyz" :rest-chars "vmpfwckzyjqdltxuognbhsrei'-a" :prefer-triggers ("v") :cregexp-support-p t)) ;; 注意:许多测试依赖这个 scheme, 所以更改名称或者删除会导致这些测试失败。 (pyim-scheme-add '(wubi :document "五笔输入法。" :class wubi :first-chars "abcdefghijklmnopqrstuvwxyz" :rest-chars "abcdefghijklmnopqrstuvwxyz'" :code-prefix "wubi/" ;五笔词库中所有的 code 都以 "wubi/" 开头,防止和其它词库冲突。 :code-prefix-history (".") ;五笔词库以前使用 "." 做为 code-prefix. :code-split-length 4 ;默认将用户输入切成 4 个字符长的 code 列表(不计算 code-prefix) :code-maximum-length 4 ;五笔词库中,code 的最大长度(不计算 code-prefix) :prefer-triggers nil :cregexp-support-p t)) ;; 注意:一些测试依赖这个 scheme, 所以更改名称或者删除会导致这些测试失败。 (pyim-scheme-add '(cangjie :document "倉頡输入法。" :class xingma :first-chars "abcdefghijklmnopqrstuvwxyz" :rest-chars "abcdefghijklmnopqrstuvwxyz" :code-prefix "cangjie/" ;仓颉输入法词库中所有的 code 都以 "cangjie/" 开头,防止词库冲突。 :code-prefix-history ("@") ;仓颉输入法词库曾经使用过的 code-prefix :code-split-length 5 ;默认将用户输入切成 5 个字符长的 code 列表(不计算 code-prefix) :code-maximum-length 5 ;仓颉词库中,code 的最大长度(不计算 code-prefix) :prefer-triggers nil :cregexp-support-p t)) (pyim-scheme-add '(pyim-shuangpin :document "与 pyim 配合良好的双拼输入法方案,源自小鹤双拼方案。" :class shuangpin :first-chars "abcdefghijklmnpqrstuvwxyz" :rest-chars "abcdefghijklmnopqrstuvwxyz" :prefer-triggers ("o") :cregexp-support-p t :keymaps (("a" "a" "a") ("b" "b" "in") ("c" "c" "ao") ("d" "d" "ai") ("e" "e" "e") ("f" "f" "en") ("g" "g" "eng") ("h" "h" "ang") ("i" "ch" "i") ("j" "j" "an") ("k" "k" "ing" "uai") ("l" "l" "iang" "uang") ("m" "m" "ian") ("n" "n" "iao") ("o" "o" "uo" "o") ("p" "p" "ie") ("q" "q" "iu") ("r" "r" "uan") ("s" "s" "iong" "ong") ("t" "t" "ue" "ve") ("u" "sh" "u") ("v" "zh" "v" "ui") ("w" "w" "ei") ("x" "x" "ia" "ua") ("y" "y" "un") ("z" "z" "ou") ("aa" "a") ("aj" "an") ("ad" "ai") ("ac" "ao") ("ah" "ang") ("ee" "e") ("ew" "ei") ("ef" "en") ("er" "er") ("eg" "eng") ("ag" "ng") ("ao" "o") ("au" "ou")))) (pyim-scheme-add '(microsoft-shuangpin :document "微软双拼方案。" :class shuangpin :first-chars "abcdefghijklmnopqrstuvwxyz" :rest-chars "abcdefghijklmnopqrstuvwxyz;" :prefer-triggers nil :cregexp-support-p t :keymaps (("a" "a" "a") ("b" "b" "ou") ("c" "c" "iao") ("d" "d" "uang" "iang") ("e" "e" "e") ("f" "f" "en") ("g" "g" "eng") ("h" "h" "ang") ("i" "ch" "i") ("j" "j" "an") ("k" "k" "ao") ("l" "l" "ai") ("m" "m" "ian") ("n" "n" "in") ("o" "o" "uo" "o") ("p" "p" "un") ("q" "q" "iu") ("r" "r" "uan" "er") ("s" "s" "iong" "ong") ("t" "t" "ue") ("u" "sh" "u") ("v" "zh" "ve" "ui") ("w" "w" "ia" "ua") ("x" "x" "ie") ("y" "y" "uai" "v") ("z" "z" "ei") (";" ";" "ing") ("oa" "a") ("oj" "an") ("ol" "ai") ("ok" "ao") ("oh" "ang") ("oe" "e") ("oz" "ei") ("of" "en") ("or" "er") ("og" "eng") ("oo" "o") ("ob" "ou")))) (pyim-scheme-add '(zhinengabc-shuangpin :document "智能ABC双拼方案" :class shuangpin :first-chars "abcdefghjklmnopqrstvwxyz" :rest-chars "abcdefghijklmnopqrstuvwxyz" :prefer-triggers nil :cregexp-support-p t :keymaps (("q" "q" "ei") ("w" "w" "ian") ("e" "ch" "e") ("r" "r" "iu" "er") ("t" "t" "uang" "iang") ("y" "y" "ing") ("u" "u" "u") ("i" "i" "i") ("o" "o" "o" "uo") ("p" "p" "uan" "van") ("a" "zh" "a") ("s" "s" "ong" "iong") ("d" "d" "ua" "ia") ("f" "f" "en") ("g" "g" "eng") ("h" "h" "ang") ("j" "j" "an") ("k" "k" "ao") ("l" "l" "ai") ("z" "z" "iao") ("x" "x" "ie") ("c" "c" "in" "uai") ("v" "sh" "v") ("b" "b" "ou") ("n" "n" "un") ("m" "m" "ue" "ui") ("oa" "a") ("oj" "an") ("ol" "ai") ("ok" "ao") ("oh" "ang") ("oe" "e") ("oz" "ei") ("of" "en") ("or" "er") ("og" "eng") ("oo" "o") ("ob" "ou")))) (pyim-scheme-add '(xiaohe-shuangpin :document "小鹤双拼输入法方案。" :class shuangpin :first-chars "abcdefghijklmnopqrstuvwxyz" :rest-chars "abcdefghijklmnopqrstuvwxyz" :prefer-triggers nil :cregexp-support-p t :keymaps (("a" "a" "a") ("b" "b" "in") ("c" "c" "ao") ("d" "d" "ai") ("e" "e" "e") ("f" "f" "en") ("g" "g" "eng") ("h" "h" "ang") ("i" "ch" "i") ("j" "j" "an") ("k" "k" "ing" "uai") ("l" "l" "iang" "uang") ("m" "m" "ian") ("n" "n" "iao") ("o" "o" "uo" "o") ("p" "p" "ie") ("q" "q" "iu") ("r" "r" "uan") ("s" "s" "iong" "ong") ("t" "t" "ue" "ve") ("u" "sh" "u") ("v" "zh" "v" "ui") ("w" "w" "ei") ("x" "x" "ia" "ua") ("y" "y" "un") ("z" "z" "ou") ("aa" "a") ("an" "an") ("ai" "ai") ("ao" "ao") ("ah" "ang") ("ee" "e") ("ei" "ei") ("en" "en") ("er" "er") ("eg" "eng") ("og" "ng") ("oo" "o") ("ou" "ou")))) (pyim-scheme-add '(ziranma-shuangpin :document "自然码双拼(不含形码)方案" :class shuangpin :first-chars "abcdefghijklmnopqrstuvwxyz" :rest-chars "abcdefghijklmnopqrstuvwxyz" :prefer-triggers nil :cregexp-support-p t :keymaps (("a" "a" "a") ("b" "b" "ou") ("c" "c" "iao") ("d" "d" "uang" "iang") ("e" "e" "e") ("f" "f" "en") ("g" "g" "eng") ("h" "h" "ang") ("i" "ch" "i") ("j" "j" "an") ("k" "k" "ao") ("l" "l" "ai") ("m" "m" "ian") ("n" "n" "in") ("o" "o" "uo" "o") ("p" "p" "un") ("q" "q" "iu") ("r" "r" "uan") ("s" "s" "iong" "ong") ("t" "t" "ue" "ve") ("u" "sh" "u") ("v" "zh" "v" "ui") ("w" "w" "ia" "ua") ("x" "x" "ie") ("y" "y" "ing" "uai") ("z" "z" "ei") ("aa" "a") ("an" "an") ("aj" "an") ("ai" "ai") ("al" "ai") ("ao" "ao") ("ak" "ao") ("ah" "ang") ("ee" "e") ("ei" "ei") ("ez" "ei") ("en" "en") ("ef" "en") ("er" "er") ("eg" "eng") ("oo" "o") ("ou" "ou") ("ob" "ou")))) ;; * Footer (provide 'pyim-scheme) ;;; pyim-scheme.el ends here pyim-5.3.3/Makefile0000644000175000017500000000361614270574720014010 0ustar dogslegdogsleg# -*- Makefile -*- SHELL = /bin/sh EMACS ?= emacs .PHONY: test clean deps compile EMACS_GENERIC_OPTS=--quick --directory . --directory .deps EMACS_BATCH_OPTS:=--batch $(EMACS_GENERIC_OPTS) RM=@rm -rf XR_URL="https://git.savannah.gnu.org/cgit/emacs/elpa.git/plain/xr.el?h=externals/xr" ASYNC_URL="https://git.savannah.gnu.org/cgit/emacs/elpa.git/plain/async.el?h=externals/async" POSFRAME_URL="https://git.savannah.gnu.org/cgit/emacs/elpa.git/plain/posframe.el?h=externals/posframe" POPUP_URL="https://git.savannah.gnu.org/cgit/emacs/nongnu.git/plain/popup.el?h=elpa/popup" BASEDICT_URL="https://git.savannah.gnu.org/cgit/emacs/elpa.git/plain/pyim-basedict.el?h=externals/pyim-basedict" ## Download pyim-basedict.pyim file from pyim-basedict v0.5.0, which commit ## is: 7495c974ada99f9fed96d8e85d8b97dabce9532c BASEDICT_PYIM_URL="https://git.savannah.gnu.org/cgit/emacs/elpa.git/plain/pyim-basedict.pyim?h=externals/pyim-basedict&id=7495c974ada99f9fed96d8e85d8b97dabce9532c" clean: $(RM) pyim-tests-temp-* $(RM) *.elc deps: @mkdir -p .deps; @if [ ! -f .deps/xr.el ]; then curl -L $(XR_URL) > .deps/xr.el; fi; @if [ ! -f .deps/async.el ]; then curl -L $(ASYNC_URL) > .deps/async.el; fi; @if [ ! -f .deps/posframe.el ]; then curl -L $(POSFRAME_URL) > .deps/posframe.el; fi; @if [ ! -f .deps/popup.el ]; then curl -L $(POPUP_URL) > .deps/popup.el; fi; @if [ ! -f .deps/pyim-basedict.el ]; then curl -L $(BASEDICT_URL) > .deps/pyim-basedict.el; fi; @if [ ! -f .deps/pyim-basedict.pyim ]; then curl -L $(BASEDICT_PYIM_URL) > .deps/pyim-basedict.pyim; fi; compile: deps $(RM) *.elc @$(EMACS) $(EMACS_BATCH_OPTS) --load ./tests/pyim-byte-compile.el 2>&1 | grep -E "([Ee]rror|[Ww]arning):" && exit 1 || exit 0 # test: compile deps clean test: compile deps @$(EMACS) $(EMACS_BATCH_OPTS) --load ./tests/pyim-tests.el $(RM) pyim-tests-temp-* runemacs: deps @$(EMACS) $(EMACS_GENERIC_OPTS) --load ./tests/pyim-emacs-init.el pyim-5.3.3/pyim-pymap.el0000644000175000017500000044043314362212573014773 0ustar dogslegdogsleg;;; pyim-pymap.el --- Pinyin map used by pyim -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2015-2020 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;; * 说明文档 :doc: ;; 这个文件是 pyim 内部使用的 "拼音-汉字" 对照表,这个对照表用来实现拼音查询功能, ;; 即,查询某个汉字对应的拼音代码。 ;; `pyim-pymap' 是使用 `pyim-pymap-build-pymap' 命令从 libpinyin-2.6.0.tar.gz 包 ;; 含的 data 文件转换得到的。 ;; 1. [[https://github.com/libpinyin/libpinyin/releases/download/2.6.0/libpinyin-2.6.0.tar.gz][libpinyin-2.6.0.tar.gz]] ;; 注意: 这个文件 *不用于* 输入法自定义词库!!! ;;; Code: ;; * 代码 :code: (require 'pyim-common) (defvar pyim-pymap '(("a" "阿啊呵腌|嗄吖锕||錒") ("ai" "爱埃艾碍癌呆哀挨矮隘蔼唉皑哎|霭捱暧嫒嗳瑷嗌锿砹诶乂欸叆毐|佁烠堨|㤅嘊伌礙䨠嬡娭鴱䀳䬵㘷䠹昹䔽娾䑂靄硋㕌呝嵦塧譪鱫䅬㱯噯敱㝶㑸䝽鎄㢊誒皚䶣馤璦皧銰躷瞹㿄㗒凒懓曖懝㗨濭藹賹阸㝵閡絠鯦譺㾢䔇㾨焥諰溰醷謁騃愛啀鑀靉敳薆厓僾餲愒壒溾") ("an" "厂广安案按岸暗鞍氨俺胺铵谙庵黯|鹌桉埯犴揞唵|匼垵垾盦|錌匎儑䬓堓䜙㜝洝阥㸩堷䅁葊荌䅖㱘㽢腤婩鵪罯晻厈貋隌䎏侒鶕䮗誝鮟䎨銨玵㟁峖䯥盫黬蓭諳痷雸韽㡋咹頇屽䤃遃㭺裺䤶萻豻啽広鞌媕闇菴馣") ("ang" "昂盎|肮卬||䬓䀚㼜昻䩕䍩䭹䭺㭿岇枊醠䒢骯㦹軮䇦") ("ao" "奥澳傲熬凹嚣鳌敖遨鏖袄坳翱嗷|拗懊岙螯骜獒鏊艹媪廒聱璈|奡嶅隩|鴁㠂㤇䴈爊䜒㠗㜜蔜簢㜩㘬㘭鰲謸䐿驁㑃䵅詏獓襖䥝慠㕭䁱扷镺㥿垇䦋梎澚䞝抝隞䚫厫䮯芺媼囂鷔擙䯠䫨柪軪嫯㿰滶翶嗸翺㟼礉䆟熝鏕㩠墽郩岰䉛蝹鼇謷奧摮嶴墺磝眑鴢泑") ("ba" "把八巴拔吧坝爸霸罢芭跋扒叭靶疤|笆耙杷鲅粑岜灞钹钯捌菝魃茇朳|妭胈蚆羓鲃鲌|鈀欛㔜鼥紦笩鈸䰾夿䩗詙䱝魞䥯罷坺䩻鮁䆉鮊㞎玐㶚馛㖠墢炦䎬犮颰䎱垻䳁㧊䳊叐䇑釟秡䟦壩哵䃻矲䮂柭䈈㭭釛皅䶕䯲㭛癹抪騃猈弝茷豝覇抜仈軷峇跁") ("bai" "百白败摆伯拜柏佰掰|呗擘捭稗|鞁|䥯贁唄㠔㼟栢㼣䴽䙓絔敗兡庍䒔䢙薭䳆㗑㗗㿟矲擺蛽韛挀㧳䠋䪹㔥竡猈襬粨粺拝") ("ban" "办版半班般板颁伴搬斑扮拌扳瓣坂阪绊|钣瘢舨癍柈|昄攽湴靽|朌怑鈑㸞褩䬳蝂絆鉡虨㩯䕰䉽粄岅螌㚘㺜肦辦辬㪵闆秚瓪賁㻞䛀埿䰉搫䈲坢䃑跘螁頒斒姅籓魬鳻") ("bang" "帮邦旁榜棒膀镑绑傍磅蚌谤梆|浜蒡氆甏|玤蚄棓塝搒|縍稖謗㔙蜯䰷挷幇㭋幚捠幫綁㮄鎊䂜鞤㾦䎧䖫邫垹㯁髈䧛䟺埲硥蛖騯嫎牓艕") ("bao" "报保包宝暴胞薄爆炮饱抱堡剥鲍曝葆瀑豹刨褒雹孢苞|煲褓趵鸨龅勹|枹|鴇怉䨌䈏䴐䨔䤖堢笣報襃㙅䭋鉋靌蕔齙㵡䥤㙸䎂窇袌㲏鮑㲒嚗犦䪨蚫宲骲忁闁駂㻄铇䳈嫑曓寚瓝珤緥㫧䳰賲鳵寶㿺勽飽鸔䭸䯽靤髱儤虣鑤媬菢寳扢嘐") ("bei" "北被备倍背杯贝辈悲碑臂卑悖惫蓓裨|陂钡狈呗焙俾碚褙埤鞴孛鹎萆邶鐾|哱琲椑棓鞁糒|㱯䱝䥯垻唄㗗䟺昁鄁愂錃㰆㼎䔒伓䠙㸢㔨㸬㤳紴鐴㸽䰽䩀䁅牬杮鵯鉳䡶偹禆憊㶔犕梖誖備貝㾱綼㣁僃鋇㓈㻗韛㛝藣郥軰䋳㷶揹俻珼狽䟛箄骳㔗㭭萯䣙苝㫲諀輩偝桮奰盃柸") ("ben" "本奔苯笨夯|贲锛畚坌栟坋|倴犇|渀㤓錛㨧逩䬱夲輽楍獖奙桳㱵㡷捹撪㮺賁燌泍軬蟦鐼炃㮥喯翉") ("beng" "泵崩蚌蹦迸绷甭|嘣甏堋琫镚|玤祊洴弸搒|㔙蜯挷㛝逬䨻䙀繃㑟奟䩬嵭䭰塴㱶誁閍鞛熢綳䳞㷯槰跰鏰埲䋽㧍漨琣錋㼞傰埄蠯伻絣菶偪痭") ("bi" "比必币笔毕秘避闭辟壁弊彼逼碧鼻臂蔽泌璧庇痹毙弼匕鄙陛裨|贲敝蓖吡篦纰俾铋毖筚荸薜婢哔跸埤濞秕荜愎睥妣芘蚍箅庳髀畀滗狴萆嬖襞擗鐾舭|坒佖沘邲诐苾咇珌祕椑皕赑鞁馝觱鲾皦|䐿㕭㿰㗉㮄紴鐴䁅綼㷶賁繴鮩䨆朇鼊䠋蜌鰏䬛堛䌟㘠䘡䀣鄨㘩縪鄪稫㠲䄶夶弻朼㡀畁㹃彃㙄䵄筆饆佊豍鉍煏畐襒魓蹕鵖䕗㡙啚䩛聛畢幣襣幤㵥㵨䭮魮潷腷㱸䁹罼悂斃躃箄鮅箆閇枈閉粊㪏貏䪐袐螕䦘檘熚䮡㪤䊧䖩疪㚰㢰㮰貱骳䎵㢶㢸鞸妼㮿柀䫁䟆㯇鏎䋔㓖䧗䯗㧙鷝韠䏢闢䟤䣥廦㻫㿫柫滭嫳篳毴㻶䏶嗶䇷㳼蓽䃾䫾䏟㵒胇踾䵗鶝䌘䉾鴓娝鸊笓紕崥怶睤肶㯅旇翍奰蘗愊贔怭屄楅驆払詖獘獙湢偪皀粃躄梐疕鎞閟駜鷩柲飶痺閈俛髲") ("bian" "变便边编遍辩鞭辨贬匾扁卞汴|辫砭苄蝙鳊弁窆笾煸褊碥髟忭缏抃|昪萹|䐔鶣豍甂鴘㴜稨猵楄牑㭓䡢籩獱䁵㵷㝸䉸鍽邉覍㦚炞閞辡㲢玣辧䒪辮辯貶㺹䪻糄柉藊㳎㣐㳒䛒揙㻞編緶惼鯾鯿䟍疺匥㺕臱頨鞕変艑汳變邊徧箯辺釆") ("biao" "表标彪镖裱|飚膘飙镳婊骠嘌飑杓髟鳔灬瘭俵摽|骉脿蔈幖熛儦藨瀌|䙳爂贆㠒標謤䔸褾鰾驃鑣墂䞄羆檦颩颮徱颷飆飇飈飍諘鏢磦㯱㯹㧼㟽淲䅺膔篻猋錶驫穮麃僄臕滮") ("bie" "别鳖憋|瘪蹩|咇|㜩柭縪襒㱸㓖㧙䟤䇷㲢鼈䠥別彆鱉虌癟䭱䉲莂龞徶㢼蛂㿜蟞䏟䋢穪㭭䌘柲") ("bin" "宾滨斌彬濒殡缤鬓槟|摈膑玢镔豳髌傧邠||䳁虨鬂儐䐔椕瀕鬢霦汃鑌驞穦豩顮瑸繽鶣馪殯檳梹矉臏賓賔髕髩擯濱濵濹㻞砏訜蠙璸贇") ("bing" "并病兵冰屏饼炳秉丙摒柄槟|禀廪邴冫栟|昺蛃|㓈誁檳梹㨀䈂倂餅琕昞稟餠栤眪䴵鈵陃偋靐癝鵧幷窉傡抦鮩庰棅仌䋑䓑䗒竝鞸綆鞆癛磝絣並怲氷併鉼鞞掤寎苪痭") ("bo" "波博播勃拨薄伯玻搏柏泊舶剥渤魄卜驳脖膊簸菠礴箔铂|亳钵帛鲅擘饽跛蘖钹趵薜檗啵鹁泺孛擗踣僰|妭砵哱浡袯桲鲌嶓镈馞欂|㔜笩鈸詙鮁鮊馛墢䳁秡䟦㼟栢㼣䰷䨌㙸嚗犦瓝㼎紴㑟挀踄謈䰊㬍餑蔔鸔簙礡㬧䬪挬猼愽缽㴾㹀敀彂噃䑈艊驋鱍䙏鉑鵓牔剝㱟鉢䭦㩧䍨䥬㩭鑮䭯蹳繴癶䍸孹㝿煿䮀䮂䒄碆䪇䶈疈䢌㪍䂍馎嶏㖕岥撥箥䢪䪬䞳犻侼蚾㶿䊿駁胉髉䫊駊䯋㟑㗘䗚䟛郣苩懪糪柭㧳䌟䄶䵄㵨檘䮡䟆䃗肑仢襎僠殕䵗䟔䟮豰袹瓟蔢㬥狛穛茷蘗餺襏譒葧襮袚鎛髆盋鋍駮帗皪壆彴") ("bu" "不部步布补捕堡埔卜埠簿哺怖璞|钚卟瓿逋晡醭钸|埗蔀|踄鈈䬏㨐䴝餢䀯㘵䴺鈽䍌鵏㙛獛歨䑰䝵荹䪁䊇䒈悑䪔咘㾟庯㚴㻉㳍勏補䳝䋠鳪峬郶䏽㱛捬䒀秿吥婄轐陠箁抪柨僄餔佈捗不歩篰尃輹鯆誧") ("ca" "拆擦|嚓搽礤||䵽傪䟃囃䌨遪攃") ("cai" "才采财材菜彩裁蔡猜踩睬||偲|䴺䰂䐆䌨縩䴭婇㥒睵財溨㒲綵䣋棌犲啋倸䌽纔採寀埰跴扐") ("can" "参残餐灿惨蚕掺璨惭|粲孱骖黪|䅟|歺傪䟃䘉㘔㜗嬠䬫嬱謲蠶蠺鰺㨻䙁驂蝅噆㥇湌慘慙㱚慚㽩䝳䑶摻䍼㺑薒殘㦧澯喰參叄叅㿊㛑㣓䗝䗞䣟蓡燦㻮䫮黲鯵䛹䳻䏼㜞鏒嘇篸囋朁憯飡嵾縿穇摲") ("cang" "藏仓苍沧舱臧|伧|鸧|倉匨艙嵢䅮㵴鑶㶓傖䢢蒼滄賶仺獊篬蔵螥鶬凔") ("cao" "草操曹槽糙嘈漕|艹螬艚屮||㽩㜖䄚䐬騲鄵愺褿襙䒃嶆䒑撡䏆㯥鏪蓸曺慒鼜鐰㿷艸肏喿懆慅傮") ("ce" "策测册侧厕|恻||萗䈟笧測㨲䔴䜺敇㩍荝筞遪側㥽䊂墄冊厠憡箣粣廁蓛矠嫧䇲拺惻幘簎茦畟筴莋萴") ("cen" "参岑|涔骖|梣|參叄叅䤁笒䨙橬硶䅾䲋㞥梫埁䯔䃡㻸汵㞤嵾") ("ceng" "层曾|蹭噌缯|鄫嶒|㬝䉕䁬碀㣒竲曽繒驓層橧") ("cha" "查察差茶插叉刹茬楂岔诧|碴嚓喳姹杈汊衩搽槎镲檫馇锸猹嵖|沄侘垞荖梌蹅|䰈䠡䑘䂳紁訍㤞䤩餷剎䕓鑔偛䁟鍤詧䡨詫靫奼疀鎈㢉㢎㢒䆛肞銟䲦䶪䊬㪯䒲㫅嫅秅嗏䟕仛䓭㛳揷㣾芆㳗釵䅊岎㜘摖㮑褨㛼捈㲼㡸䛽挿艖扠査臿扱") ("chai" "差拆柴|钗豺侪虿瘥|茝|䜺䐤訍䡨蠆䘍儕祡㑪袃芆喍犲㾹囆㳗䓱釵㦅㼮齜偨") ("chan" "产单阐缠掺禅颤铲蝉搀潺|蟾馋忏婵孱觇廛谄谗澶骣羼镡躔蒇冁挦巉镵辿刬|旵浐梴啴瀍襜儳韂|䴺㨻摻䫮䳻㬄簅㔆嬋嬓鐔䤘攙䜛脠䀡㸥䠨䤫䐮䴼嘽鄽䥀酁譂蕆㵌㹌摌䑎䵐獑煘灛幝饞硟繟䡪顫䡲㙴繵䩶剷湹潹㙻㹽䱿䂁㦃㢆讇纏纒讒誗覘䪜㢟㶣㺥醦袩禪單䊲閳諂囅㯆惉鋋棎䣑鋓鏟闡壥蟬䧯懴懺滻緾讖䩥㺗㚲螹䦲緂裧斺榐辴欃產産丳瀺剗単艬鑱嵼劖嚵燀毚磛僝幨僤儃摲蟺襢鉆") ("chang" "场长厂常偿昌唱畅倡尝肠敞倘猖娼裳徜昶怅|嫦菖鲳阊伥苌氅惝鬯玚|鲿|厈䠀倀䠆萇嘗甞償锠琩場焻㙊䕋兏䩨腸镸瑺畼晿㦂嚐膓暢誯悵閶䗅淐僘鏛廠㫤仧鯧裮䯴瓺鋿椙闛瑒鼚錩鱨塲長厰粻韔鋹") ("chao" "超朝潮炒钞抄巢吵剿绰嘲|晁焯耖怊|弨槱|鼂鼌樔鈔鄛䬤眧欩䰫䄻謿轈罺煼禉䎐㶤麨㷅巐觘䏚濤仦仯趠綽漅劋焣䫸窲粆牊䳂䲃䮓訬摷巣勦趫搯") ("che" "车彻撤尺挚扯辙澈掣|坼砗屮|㬚|䤁䨁㨋唓頙䜠伡爡䰩㔭㵃聅㥉㱌轍㵔偖䁤硨硩䑲奲䒆莗㾝䚢䞣瞮徹車㯙迠俥䧪㿭䋲烲勶䛸蛼揊喢㒤㤴謵㳧䊞烢撦摰詀呫") ("chen" "称陈沈沉晨琛臣尘辰衬趁忱橙郴|娠宸谌碜嗔抻榇伧谶龀肜胂瞋|飏疢棽煁|謲䗞傖硶醦贂鈂霃樄謓伔堔愖䜟䤟夦訦㴴踸敐屒齓齔鍖穪襯陳㕴塵捵敶㽸㲀莀趂䢅䢈䞋墋麎莐讖䚘䒞䆣嚫螴䢻趻薼諃䣅鷐䫖裖軙曟䟢磣迧櫬㧱㫳諶藽揨跈綝䀼儬瘎㥲䏹䫈縝侲茞儭蔯稱搷賝瘨桭") ("cheng" "成程城承称盛乘诚呈惩撑澄秤橙骋逞瞠|丞晟铛埕塍噌伧蛏柽铖酲裎樘浈枨琤|宬珹珵偁庱牚赪澂憕|碀䁤穪䚘脀騁㨃洆䄇椉娍瀓䀕堘崝㼩騬脭爯挰䔲頳阷鐺㐼睈䁎饓塖靗摚牜湞晠塣筬畻浾絾荿掁㲂憆檉徎撐䆑䞓窚誠䮪侱䆵䆸㞼竀䫆䗊䧕棖泟埥棦揨鋮懲蟶䇸峸緽鏿僜檙矃溗橖浧氶撜埩鏳稱橕乗赬悜郕虰踜朾") ("chi" "持吃池迟赤驰尺斥齿翅匙痴耻炽侈沱弛叱啻|坻哆郗眙嗤墀哧茌豉敕笞饬踟踅蚩媸魑篪沲褫彳鸱螭瘛痄眵傺搋|佁胣栻瓻痓摛漦䗖|誀䐤䰩㔭㥉䜄㔑䈕栘謘耛㘜䔟鴟䠠䰡伬䤲䜵訵䜻㱀恀筂噄鵄荎齒鉓慗杘䙙㽚䑛㙜恜齝腟遟鵣恥汦彨歭遲鉹齹灻㡿赿㢁傂㒆蚇䮈箈㢋趍粎憏銐垑䶔侙㮛妛瞝徥䪧趩㢮徲袳馳㞴㶴䶵麶誺䮻岻䊼䞾熾貾㞿㟂䛂翄㳏黐勑淔懘鷘翤裭飭忯䳵䟷拸痸叺㓼䇼姼㓾烾俿䀸慸䧝軧捇卙䏧狋迡樆䄜邌㷰雴汖紕㩽湁卶翨菭蝭脪㥡趐謻㑜呹沶胵饎戠欼遅呎扡癡遫歯摰彲絺誃箎鶒蚔喫蚳抶勅跮竾鍉彽瘈柅呬乿袲騺迣鳷") ("chong" "重种充冲崇虫宠忡憧|舂茺铳艟|珫翀埫摏漴|嘃崈褈䌬祌㹐蹖衝蝩浺隀銃䖝徸痋㧤䳯蟲寵㓽㓼䡴爞㮔䆹偅蹱喠緟湧沖傭揰憃罿") ("chou" "筹抽绸酬愁丑臭仇畴稠瞅踌|溴惆俦瘳雠帱杻|尨侴婤椆犨|䔏儔㐜吜栦䌧㨶䌷㤽籌䥒絒魗㵞酧幬杽疇躊嚋讎讐醔䲖皗醜㦞殠綢莥犫䊭䪮憱薵醻矁䓓雔菗㿧䛬臰㛶䇺㘜遚㿒㾄鈕㨨跾䱔牰鮋搊丒嬦紬詶鯈篘懤裯燽眣偢怞") ("chu" "出处础初除储畜触楚厨雏矗橱锄褚滁躇|怵绌搐刍蜍黜杵蹰恹亍樗憷楮㤘俶|柷琡摴濋斶|㜗㗰豠䎌㘜踀䠂礎㤕㔘椘耝㼥䠧欪儲䜴嘼絀㙇敊㕏蕏㕑䙕處䙘遚㡡齭幮荲䅳㹼齼岀㶆䦌趎䖏犓躕傗貙檚䎝䮞䎤䊰墸芻拀滀䧁臅櫉竌泏竐廚雛䟞䟣鋤櫥懨藸觸鯺䇍珿摢䶥㗙櫖鸀埱䅷㾥媰䐍䐢㾻諔炪儊鄐耡蠩鉏豖詘歜齣蒢閦蒭鶵処跦篨慉菆蓫迍") ("chuai" "揣|踹啜嘬搋膪||䴝㱀㪓㪜䦟䦤䦷腄欼膗") ("chuan" "传川船穿串喘|椽舛钏遄氚蝽巛舡|堾圌|鐉舩輲踳㼷歂汌瑏㱛䁣傳暷篅㯌賗僢釧諯鶨椯剶丳荈玔猭伝") ("chuang" "创床窗闯幢疮|怆艟疒|漴噇橦|䆫囪刅瘡戧愴搶漺㵂獊牎剏摐牕㡖剙䭚摤䡴創䚒䎫窻闖䃥䇬䄝傸磢㼽凔刱牀憃窓朣") ("chui" "吹垂锤炊椎陲槌|捶棰|倕圌魋|䞼㷃䕓錘䄲娷顀腄䍋桘㥨湷㝽㩾㓃諈菙䳠䅜䜅甀搥鎚箠龡埀") ("chun" "春纯醇淳唇椿蠢|鹑朐莼蝽䏝|堾焞瑃|䮞踳萅䐇䐏䔚䄝㸪萶㝄偆㝇䥎陙㵮浱睶湻鶉媋憌䞐蒓醕暙鶞膥䦮㖺箺䫃櫄䓐䏛滣㿤䣨䣩旾䡅輇賰鰆純漘錞脣輴杶鯙蓴惷犉芚橁") ("chuo" "辍缀绰戳|啜龊踔辶|逴惙婼|拺鏃娖輟䄪腏繛鑡齪酫齱䍳㲋䂐䮕㚟趠䆯涰辵嚽綽諁䇍䓎䃗䋘磭珿㪕娕跿箹孎䄌㪬吷歠婥畷醊擉") ("ci" "次此差词辞刺瓷磁兹慈茨赐祠伺雌疵|蚝鹚糍呲螅茈粢跐|佽泚玼堲莿|厠廁㘂甆䰍䨏䈘礠嬨栨㤵㘹刾㠿㹂㩞詞䭣㡹赼㢀趀䆅螆皉薋垐㞖庛辝䂣辤䖪辭枱䦻䲿鷀珁䳄柌䛐䳐賜䓧㓨濨䧳䯸䗹飺縒髊齹㾊紪㐸栜鈶蠀鴜姕茦餈朿佌絘骴蛓偨鮆澬鶿") ("cong" "从丛匆聪葱囱|琮淙枞骢苁璁熜|悰|樅欉漗騘爜錝蔥謥焧樬樷㼻婃鍃驄灇慒䉘聡聦孮鍯聰繱䕺徖瞛從悤䆫暰誴藂棇蟌総鏓叢忩賩囪燪緫蓯㗰篵䳷楤䡯䰌憁碂潨漎怱潀瑽従鏦賨鍐菆") ("cou" "凑|辏腠楱||輳㫶㔌湊") ("cu" "促粗簇醋卒蹴猝|蹙酢蔟殂徂㤘||鼀瘄䠓㰗䠞䬨脨縬䥄噈䥘豠䙯梀麁䎌䢐趗殧趨鏃䃚䓚䟟㗤䛤蔖憱踀娕蔍趥誎䣯踓蹵麆踧瘯麄麤觕怚顣踤") ("cuan" "窜攒篡|蹿氽撺爨汆镩|僔|攅㸑簒䰖攛㠝攢㵀㭫鑹劗䆘躥殩熶䞼竄巑櫕濽穳襸䂎灒鋑篹欑菆") ("cui" "衰催崔脆翠萃粹摧璀瘁|悴淬橇啐隹毳榱|崒缞漼|䢪䔴脃琗䄟紣脺襊㵏獕㱖慛㥞㝮䆊墔皠疩䊫膬䂱綷䃀㳃㷃翆臎㯔凗㧘鏙㯜濢㷪槯忰嗺䧽㓹繀熣䘹嶉倅伜焠顇啛粋趡膵竁磪縗踤椊") ("cun" "村存寸蹲|忖皴邨|瑳|刌䍎籿澊袸竴侟䞭拵吋洊踆墫") ("cuo" "措错磋挫搓撮|蹉锉厝嵯痤矬瘥脞鹾|玼莝棤瑳酂|䥘㭫襊䰈縒蔖䠡䐣䐤逪錯䴾睉剒䑘虘䱜㽨硰嵳遳歵鹺莡蒫䂳侳銼㟇髊䣜䟶齹㿷諎躦夎酇剉齰醝蓌斮") ("da" "大达打答搭沓瘩|嗒挞哒耷鞑疸靼褡笪怛妲跶褟|垯荙炟溚阘|䐊匒㜓眔鐽畗詚噠䩢䵣畣㙮剳䑽呾㾑墖撘箚鎝墶韃㯚䃮㿯䳴㟷蟽汏䪚毼䪏躂羍龖㯓迖㗳矺笚㩉觰謷逹荅達繨咑薘闒僤搨鎉龘") ("dai" "大代带待贷戴袋歹呆逮岱傣怠殆黛甙|埭绐玳呔迨骀嘚|轪媞叇|䲦䠠䈆帒簤㐲霴帶瀻紿獃瑇汏蹛酨䚞䚟㶡䒫㞭貸㯂㿃曃柋軑忕㻖廗軚懛跢軩黱㫹緿蝳箉駘鴏詒帯靆艜襶遰") ("dan" "但单石担丹胆旦弹蛋淡诞氮郸耽檐赡殚|惮儋眈疸澹掸亻膻啖箪钽聃萏瘅赕亶|疍惔憺|譂䡲繵覘單伔愖呾蹛㔊帎刐舕頕簞䨢匰鄲䨵䄷耼嘾㵅腅䱋㽎饏灗癚䭛䉞噡䩥㕪潬衴䉷聸㡺㱽啿媅妉沊誕㺗憚撣嚪殫玬䮰㲷澸暺膽馾䳉擔㗖狚觛㫜柦䃫瓭駳黵泹㯯㐤贍醈䦔䊤䏙娊唌䗺䪴鴤単燀砃蜑甔紞鴠霮丼弾彈噉癉襌酖啗幨窞撢禫躭僤髧勯劻儃蟺贉餤黮皽抌黕") ("dang" "当党档荡挡宕|砀铛裆凼菪谠垱珰玚|筜|鐺礑欓蘯圵氹逿䑗灙襠艡譡嵣當瞊䦒檔璗讜澢趤碭䣊壋擋䣣闣黨雼瓽偒潒崵婸儅愓簜攩簹蕩噹璫盪蟷") ("dao" "到道导岛倒刀盗稻蹈悼捣叨祷|焘氘啁纛刂帱忉捯|舠鱽梼|濤㨶幬䊭薵㔑䮻䣣㠀搗䌦朷幍衜衟噵䆃嶋嶌隝檤隯禱嶹䲽䧂軇㿒釖瓙盜島燾菿虭嘄㧅翢絩箌陦導稲魛禂壔擣翿") ("de" "的地得德底|锝嘚扽||㝶㤫㥀鍀㥁恴㝵䙷䙸悳淂棏㯖脦扥徳惪農") ("dei" "得|嘚||䮻哋") ("deng" "等登邓灯澄凳瞪蹬|噔磴嶝镫簦戥|澂憕璒|䔲嬁鐙鄧䠬霯邆隥䒭墱䮴覴櫈燈僜竳朩豋") ("di" "的地第提低底抵弟迪递帝敌堤蒂缔滴涤翟娣笛棣荻谛狄邸嘀|砥坻诋嫡镝碲骶犒氐莜柢籴笫羝睇觌玓杕|轪茋浟菂媂髢禘䗖踶鞮蹢|䲦赿䞾䨢䨀樀㰅焍蔐鸐頔唙䴞怟眡䨤㼵䀸阺䀿䱃奃詆啇㹍坔䍕摕䩘坘偙䩚聜遞䵠腣潪鉪䑭䑯䱱㡳虳楴豴祶慸㭽嵽嚁隄㦅㪆墆趆掋䶍䢑墑梑肑袛䂡䮤㢩䊮馰嶳䞶覿僀埊䣌滌䏑鏑苖㣙䧝埞拞締䟡藡仢諦軧旳糴䯼仾磾扚魡儥埅鬄碮苐俤䪘眱䐭䏄蚳哋甋蔋逓蔕弤渧鍉呧靮啲牴敵彽梊螮藋觝菧釱篴珶廸適惸諟揥墬遰厎蝃") ("dia" "|嗲||") ("dian" "电点店典奠甸碘淀殿垫颠滇癫巅惦掂|癜玷佃踮靛钿簟坫丶阽|扂琔磹|䀡頕䩚㸃蜔錪㼭鈿橂䍄㥆蕇奌顚顛婝敟㵤㝪嵮婰癲齻墊㶘㞟厧澱㚲嚸壂䧃槇䟍巓巔槙點㓠䓦橝痶蒧琠攧瘨敁蹎傎痁電跕腍驔詀") ("diao" "调掉雕鸟吊钓刁貂凋|碉鲷叼啁莜踔铫铞汈|窎椆嬥|䳝䄪䄷䲽伄訋弔䔙鈟鼦弴瘹䠼鑃䉆扚奝魡虭鵰䵲㹿鮉㪕瞗銚㒛殦䂪銱䂽調鯛釣竨鳭矵鋽㢯錭絩䳂䯾軺雿鵃淍㣿藋琱屌彫誂窵蛁蓧鉥匽劚") ("die" "跌叠蝶迭碟爹谍牒|耋喋堞鳎瓞鲽垤揲蹀|昳咥绖䏲楪|䳻蹛嵽㦅鰈耊褋氎䴑挕戜䠟㬪䘭眰褺牃詄㥈恎聑艓㑙㭯㩸㩹䲀嶀疂趃䞇疉疊䞕䮢䪥㲲㲳㦶䳀胅峌諜㻡曡惵苵臷㷸㫼啑䩞崼鰨怢㤴鞢軼殜挃螲䫕㗧跮哋攧眣蜨絰畳镻跕槢柣") ("ding" "定订顶丁鼎盯钉锭叮仃铤|町酊啶碇腚疔玎耵|萣|訂頂帄鼑㼗娗錠鐤甼㴿顁㝎饤奵嵿檙掟碠㫀忊鋌濎釘矴磸㝪㞟䵺艼椗靪虰薡飣") ("diu" "丢|铥||颩丟乣銩") ("dong" "动东董冬洞懂冻栋侗咚|峒氡恫胴硐垌鸫岽胨夂||㨂挏笗霘戙嬞崠崬氭㼯㜱倲昸娻㑈䅍䵔腖東䍶鶇䞒䂢㢥墥㖦炵箽菄㓊諌働凍動峝棟鯟㗢駧埬絧詷䆚㣚姛狪勭迵鴤㣫揰鼕蝀涷苳蕫湩騆") ("dou" "都斗读豆抖兜陡逗窦|蚪痘蔸钭篼||䇺䄈唗唞鬥䬦鬦阧㨮吺䕆兠浢敨䕱橷饾讀㢄閗枡斣梪㞳㪷鋀㷆竇㛒郖䛠毭瞗㤱㓸氀侸鈄酘餖鬪鬬鬭脰荳枓読闘") ("du" "度都独督读顿毒渡杜堵赌睹肚镀渎笃|嘟犊妒牍蠹橐椟纛碡黩芏髑厾阇||䰩㓃讀㹍瀆䄍錖䐗䈞儥蠧騳匵簵嬻琽䀾帾㸿豄䅊鍍牘鑟獨㱩靯荰䙱蝳㾄䪅暏醏螙涜犢䲧覩妬殬䢱䮷皾瓄韇槖櫝凟篤韥賭䓯䫳黷秺䟻裻剫䐁樚晵䦠㒔㞘鍺㧻㡯噣罜剢読頓贕斁讟喥殰闍睪襡韣陼") ("duan" "断段短端锻缎|煅椴簖|塅瑖|篅褍耑䠪鍛籪剬㱭葮偳鍴媏躖斷㫁緞㟨腶碫毈") ("dui" "对队敦兑堆|碓镦怼憝|祋|㨃桘䬈對鐓㠚鐜㬣頧瀩䔪䨴䨺䬽㙂兊兌轛嵟塠陮㵽隊綐垖憞薱㟋䇏磓㳔䯟懟䇤濧濻痽䏨膭謉㢈瀢㢂鈗鴭搥錞譈対鋭杸啍") ("dun" "不吨顿盾敦蹲墩囤沌钝炖|盹遁趸砘镦礅惇楯蹾坉扽||鐓鐜憞伅逇鈍䤜踲蜳崸㬿驐腞潡噸撉躉犜鶨墪撴燉橔頓遯庉") ("duo" "多度夺朵躲铎咄堕沱舵驮垛惰|锗哆踱跺掇剁柁缍沲裰哚埵杕|饳剟亸|㤞䁟奲袳㪜腏跢悳䄍挅挆鬌㔍夛崜䠤茤䤪鈬尮椯刴鐸䤻䐾䙃陊陏㙐敓䩔桗襗敚䅜䙟敠䩣䙤䑨㥩奪剫䍴鵽貀嚉袉莌趓垜憜綞炧炨墮墯躱馱䒳鮵㖼䫂軃㛆㛊痑㻔凙㣞痥跥㻧䯬毲㧷飿隓跿䲊㨊䝐鍺㡯誃喥朶敪嶞嚲駄柮媠沰柂硾") ("e" "额阿俄恶鹅遏鄂厄饿峨扼娥鳄哦蛾噩愕|讹锷垩婀垭鹗萼桠谔莪腭锇颚呃阏屙苊轭蚵硪丨钶|姶涐堨崿|娾呝匎䜙洝痷騀蘁㼂䄉堊㠋鈋椏砐鰐餓圔唖訛頟㼢琧砨㔩㼰阸戹搹䔾娿蝁湂硆䝈㡋睋譌遌額㕎顎䕏偔鍔蕚鵝啞鵞豟魤䑥魥㱦鑩䑪䱮䙳㩵屵鱷䩹歺卾蚅岋㦍讍誐䆓貖㮙鶚覨䞩䖸妸咹閼㖾妿磀㗁㷈㗉峉䓊㧖䛖䳗迗䳘軛䣞埡諤㟧鋨峩僫䳬櫮珴㓵軶䫷廅鰪齃佮頋歞閜擜砈䚰礘㩽䛩㧴㣂㫊㛕齾囐隲頞搤阨餩吪堮齶詻皒枙咢悪嶭惡囮痾輵噁") ("ei" "|诶欸||誒") ("en" "恩|嗯唔摁蒽||䬶奀䭓䭡䅰㕶煾䊐糦峎饎") ("er" "而二尔儿耳迩饵洱蛾|贰铒珥佴鸸鲕|陑耏咡峏谞臑|餌㜨栮鴯眲䌺荋聏兒轜鉺誀㒃㖇邇㮕侕䮘鮞䎟䎠隭貮䎶㚷袻㢽檽㛅䋙毦䋩䏪㧫䣵髵粫杒髶腝輀弍洏弐尒尓栭唲樲刵爾衈児貳薾駬胹陾卲") ("fa" "发法罚乏伐阀筏|砝垡珐|酦擿|笩彂撥貶㳒栰㘺琺橃灋蕟罰佱罸㕹瞂醗傠䒥閥醱䂲疺姂䇅藅髮㛲䣹茷発發髪沷") ("fan" "反范犯繁饭泛翻凡返番贩烦帆樊藩矾梵蕃|钒幡畈犭蘩蹯燔璠氾|墦|䕰㾱噃䪻柉㳎㴀䀀㤆訉㸋嬎嬏䌓㼝䀟舤匥舧䐪瀪礬㠶瀿㝃䉊䡊杋橎襎䉒鱕㕨畨煩䭵㽹奿㺕㶗䪛䒠薠憣䪤䒦䊩販䮳羳䛀緐軓盕旙忛飜僠凢䋣凣棥䋦釩勫軬飯飰䣲䫶滼㮥楓䟪婏犿㛯払鐇嬔蠜鄤笲笵汎籓轓繙魬籵膰颿範旛鷭渢") ("fang" "方放房防访纺芳仿坊妨肪邡|舫彷枋鲂匚钫昉|牥蚄鳑|眪䉊鈁㤃眆鴋昘鰟紡訪㑂㕫魴汸䦈䢍鶭䲱趽埅旊㧍㯐瓬䰃錺倣淓髣") ("fei" "费非飞肥废菲肺啡沸匪斐蜚妃诽扉翡霏|吠绯腓痱芾淝悱狒榧砩鲱怫篚镄|朏剕棐|墢㸬杮㾱㓈賁䍨䞳犻䯋䟛㹃䒈橃蕟䀟䰁渄猆䈈萉䠊㔗騛鼣餥蜰昲䤵䨽䨾䕁靅㩌㵒婓䑔蕜靟䕠䉬㭭㥱䆏厞䚨誹費胇曊緋䛍飝櫠鯡廢蟦裶濷橨紼陫婔騑鐨癈奜屝馡疿廃飛俷蕡笰胏") ("fen" "分份纷奋粉氛芬愤粪坟汾焚皂酚|吩忿棼玢鼢瀵偾鲼棻坋|翂豮|朌肦獖㱵賁燌㻞䀟䢍䆏䴅弅朆帉砏昐鈖紛訜㸮餴鐼饙鱝橨奮衯㥹䩿炃岎羒馚蚠妢憤梤㮥馩隫墳蒶㖹膹黂㷊㿎秎燓糞䯨僨黺䫞葐竕鼖坆轒兝蕡幩魵豶枌蚡羵濆雰鳻錀") ("feng" "风丰封峰奉凤锋冯逢缝蜂枫疯焚讽烽|俸沣酆砜葑唪沨|浲崶赗|䩬熢䵄䒠㕫瘋鴌猦漨焨縫蠭甮蘴鄷堸捀艂灃煈靊偑摓楓湗䙜㡝㵯桻䩼㦀犎莑檒妦馮麷碸篈䏎鋒鏠凨䟪凬凮峯鳯鳳寷諷仹僼盽舽炐鵬埄㛔夆渢豊豐覂綘風飌賵炰鉥") ("fo" "佛|||㤇坲髴仸仏") ("fou" "否|罘缶芣|垺|䬏鴀缹缻剻殕䳕裦雬哹妚紑炰") ("fu" "府服副负富复福夫妇幅付扶父符附腐赴佛浮覆辅傅伏抚赋辐腹弗肤阜袱缚甫氟斧孚敷俯拂俘咐腑莆孵芙涪釜脯|茯馥绂讣呋罘麸蝠匐芾蜉跗凫滏蝮驸绋蚨砩桴赙菔呒趺苻拊阝鲋怫稃郛莩幞祓艴黻黼鳆茀芣|㕮㳇玞韨枹砆洑垺琈䓛鄜榑簠|蓲㞎颰㚘䈏䥤㾱䬪㝿䒄㗘柭畐䭮柫䍌䪔䳝畗㷆萉㔗昲㡝髴䳕哹䘀訃䘄㠅錇娐㜑鰒㤔輔鴔伕䌗䨗縛䘠怤焤紨稪萯䔰㤱䨱椱紱鬴䠵甶嘸輻㬼紼踾䌿栿乀艀癁詂䩉畉䡍䕎㙏婏鍑䍖㵗䵗鉘虙陚蝜鉜筟鍢絥婦䑧蕧豧㽬捬荴乶䭸䝾䵾坿彿䒀㪄鮄䎅㚆䒇㾈暊妋媍枎綒鮒澓㚕垘䪙膚䮛䞜袝鶝䞞邞負䦣䂤炥蚥冨復麩岪撫颫麬䞯粰麱璷䞸玸冹䗄姇翇旉㟊峊俌䫍竎糐䟔胕蛗㫙盙駙䫝䧞㓡釡賦鳧䋨諨鳬䟮緮懯烰䯱棴軵䋹鳺賻䃽䯽秿荂郍邚捊圑纀箁䞤汱撨酻袚払嬔仏尃蜅複鈇褔帗刜弣頫笰輹葍祔罦偩鵩衭咈綍箙沷蚹鯆韍柎郙泭巿俛襆痡沕湋") ("ga" "夹轧咖嘎尬噶旮伽|尕呷钆尜||嘠錷玍軋釓魀") ("gai" "改该盖概溉钙丐芥|赅垓陔戤胲|荄晐|䬵䶣匃匄漑鈣絠摡畡㕢乢葢豥絯屲該祴隑㮣䪱瓂郂賅㧉忋賌峐䏗姟槩槪杚䐩阣侅蓋") ("gan" "干感赶敢甘肝杆赣乾柑尴竿秆橄矸淦|苷擀酐绀泔坩旰疳澉玕扞|虷浛嵅鳡|玵豃佄䔈稈贑䤗贛倝蜬尲簳尶尷紺攼詌䵟鱤衦汵乹幹桿亁㺂芉檊粓趕皯䲺涻迀䯎凎忓䇞仠飦䃭盰鳱凲笴㔶鰔魐漧錎䊻㓧灨筸咁榦骭諴") ("gang" "港钢刚岗纲冈杠缸扛亢|肛罡颃戆筻舡冮|矼堽|頏戅戇崗䴚焵罁塂罓㽘剛牨犅掆碙鎠岡綱㟠棡㟵鋼堈笐疘槓釭犺阬") ("gao" "高告搞稿膏糕镐皋|羔锆杲郜睾诰藁篙缟槁槔|筶|䨢㵆獋勂稁縞攪夰餻吿祮橰煰祰㚏皐㚖羙禞誥鎬㾸檺菒滜韟䗣臯鋯鷱藳槹槀叝䓘鷎鼛稾睪暠髙櫜") ("ge" "个合各革格歌哥盖隔割阁戈葛鸽搁菏胳舸疙铬骼蛤|咯圪阖镉砝颌仡硌嗝髂鬲膈纥袼搿塥哿虼牁|郃滆|鉿頜㭘詥秴葢䘁嘅愅紇個匌謌䈓戓騔䐙鴚䨣戨鰪㨰笴㠷鴿齃呄晄敆敋䩐㝓獦㵧牫佮魺䕻鉻䪂鲄䢔鎘䆟閣閤麧鮯㦴鎶鞷䪺㪾䧄槅㗆䛋韐滒蛒裓䗘韚䫦嗰擱㷴臵諽䛿杚牱鴐鉀䩡鞈吤䅥鵅鮥䬣㓣鎑䣬猲蓋挌茖渮輵轕亇箇肐擖觡仮扢犵") ("gei" "给|||給") ("gen" "根跟亘|艮哏茛||刯㮓亙䫀㫔揯") ("geng" "更耕颈庚耿梗埂羹哽|赓绠鲠|浭暅鹒|䨣刯亙䌄搄縆頚堩挭頸恆畊䱍䱎絙絚䱭䱴莄綆㾘羮䋁鯁賡菮揯峺䢚䎴鶊骾郠緪") ("gong" "工公共供功红贡攻宫巩龚恭拱躬弓汞|蚣珙觥肱廾|唝|䱋渱䍔玜䐵䔈贛匑㼦礦㤨愩㔶摃幊䡗杛㭟塨穬鞏龏鞐龔䢚貢㺬䂬宮躳厷碽羾銾㓋㫒鋛䇨㧬蛬㯯拲觵髸糼輁㕬魟嗊疘釭栱篢") ("gou" "构购够句沟狗钩勾苟垢枸|篝佝媾诟岣彀缑笱鞲觏遘|泃耇姤雊馌|䪷豰耈耉㜌㨌鈎夠褠唦茩簼訽㝅㝤鉤詬䝭坸煹豿䞀撀㺃瞉傋溝覯芶蚼玽構䃓㗕緱㳶購㽛袧痀䵶䐟搆茍冓韝軥呴") ("gu" "股古顾故固鼓骨估谷贾姑孤雇辜菇沽咕呱锢钴鹄箍汩|梏痼崮哌轱鸪牯蛊诂毂鹘菰罟嘏臌觚瞽蛄酤牿鲴榖|羖堌䓛蓇馉瀔|怘䉉啒磆吿唂唃夃䀇㼋頋縎稒崓鼔䀜笟鴣䀦䐨錮䀰蠱愲鈲尳脵餶鈷焸䜼詁轂䍍杚䍛鵠顧䡩橭䵻㽽䅽㚉鮕䶜薣䮩㒴㾶皷䊺鶻皼淈賈㯏糓嗗狜棝鯝䓢柧軲嫴㧽苽櫎䡰䇢穀罛扢祻箛榾凅蛌泒盬僱軱濲惸呴") ("gua" "括挂瓜刮寡卦呱|褂蜗聒剐胍诖鸹栝脶|坬蹐|焻㓡諣䏦䀨捖䯏䈑瘑頢鴰踻葀歄腡啩剮煱蝸詿劀冎趏掛颳㒷膼銽懖叧緺袿㱙咶騧筈絓罣罫髺銛") ("guai" "怪拐乖|掴夬||䃶㽇癐箉䂯䊽㷇叏㧔廥摑罫恠枴旝柺") ("guan" "关管观馆官贯冠惯灌罐莞纶棺|矜倌鹳鳏盥掼脘涫琯瓘毌|婠蒄祼筦爟鳤|閞鵍䂯樌舘鸛鰥㴦錧輨館䌯礶䘾潅罆癏䙛摜鱞慣遦䩪䙮鱹䝺䪀覌䦎䲘䎚㮡窤貫綸悹悺觀䗆鏆䏓闗䗰泴淉瘝丱鑵関観矔雚關痯") ("guang" "广光逛犷|胱咣桄|垙洸珖|撗趪䍍輄茪灮獷侊炗炚炛黆矌櫎僙㫛烡廣臦臩姯㤮硄俇挄広飡銧謭迋") ("gui" "规贵归轨桂柜圭鬼硅瑰跪龟匮闺诡|癸炔鳜桧皈鲑刽晷傀妫炅沩庋簋刿宄匦氿|邽姽珪硊跂筀廆僇鬶|㱦鳺䃽櫰䃶禬癐嬀䌆昋䰎椝猤䤥䠩匭攰攱㔳㨳䐴㸵鬹䙆陒鱖襘潙䁛鱥祪摫詭敮䍯䍷㙺㩻䝿楿亀瞆㪈䞈溈劊劌規窐檜龜䞨閨暩庪厬膭䖯媯㲹鞼袿䣀櫃䇈瓌軌郌䳏蓕巜蟡嫢䯣槣觤㧪蛫胿簂䐩䤆謉䈐椢騩蘬匱湀撌槶䟸瞡赽朹㰪䮹螝吷鴂帰恑歸佹溎垝璝嶡鮭貴槻槼鐀茥瞶趹巂") ("gun" "滚棍辊|衮磙鲧绲丨||睔㨰鰥䙛㔳䜇輥謴㙥䵪睴鮌掍袞璭䎾䃂緄㫎蓘裩㯻滾錕惃袬裷緷蔉鯀") ("guo" "国过果郭锅裹帼涡|椁囗蝈虢聒埚掴猓崞蜾呙馘馃粿|腘|楇瘑矌櫎錁簂䤋漍䬎鈛餜堝渦䐸䴹鐹腂鍋彍過摑慖幗䙨啯㕵㶁㞅㚍墎䆐㖪綶䂸㳀濄惈蟈淉槨囻埻彉蔮㗥咶圀國嘓輠聝膕咼菓囯囶") ("ha" "哈虾蛤|铪||蝦鉿奤") ("hai" "海还害孩亥咳骸嘿骇|氦嗨颏胲醢嗐|咍浬|䠹㱚䝳拸䍖䂤㨟㤥頦䠽㜾饚䱺酼㺔㦟䇋䯐㧡駭烸㕢絯䪱郂㧉䜕妎餀還侅皁") ("han" "汉韩含旱寒汗涵函喊憾罕焊翰邯撼瀚憨捍酣悍|阚鼾颌邗颔蚶晗菡顸犴焓撖扞|虷垾浛琀崡嵅蔊暵㘎|厈貋䎏笒䦈䏎㸁猂䈄䐄圅頇攌䌍㨔㘕㘚頜甝䨡娢㜦㼨蜭䤴䘶頷譀䥁豃㵄佄顄㙈㽉㵎䍐䍑㙔䁔晘筨浫㙳㽳㑵屽魽䕿㮀嚂䶃涆㒈㪋澏梒䖔皔㺖莟馠㖤㲦䮧㢨䎯馯㶰銲炶傼鶾䓍鋎㟏㟔䗙䛞闞鋡嫨闬䧲䫲䏷哻駻凾䓿蛿蜬攼汵仠鳱䗣鬫㰹㺝蘫㦑肣鈐欦顩䜗軒豻唅漢谽睅晥閈螒熯淊韓雗釬迒榦椷歛") ("hang" "行航杭巷夯蒿吭珩|酐桁沆绗颃鸻||䴂頏䘕㤚䀪絎筕魧蚢貥䦳䲳斻苀䣈䟘忼雽䂫㬻䢚㰠邟妔迒笐") ("hao" "好号毫豪耗浩郝皓昊镐蒿壕|灏嚎濠蚝貉颢嗥薅嚆鸮|诐淏鄗皞|椃䬉㬔蠔㠙鰝瀥昦㘪儫㬶嘷㝀㵆獆籇獋恏噑獔聕㩝灝䝞號虠䝥顥晧㙱㕺悎傐皡暤皥㚪暭鶴䒵㞻䚽䪽侾勂滈曍䧚哠狢䧫䯫峼鎬竓藃譹薃澔皜秏諕暠薧呺茠") ("he" "和合河何核贺喝赫荷盒鹤吓呵酶禾菏壑褐涸|阂阖劾诃颌嗬貉曷翮纥蚵盍饸盉鞨|郃垎隺龁滆鹖熇翯龢|䙓㚘噈㾑䮤㻧䯨頜㙳㪋㲦鶴狢爀萂焃礉鸖蠚㬞㔠䴳訶訸楁䅂煂㹇癋靎靏㵑㭘啝㕡䕣詥㕰㭱䵱㥺䚂䶅熆嚇貈㪉咊䎋碋袔澕䢗䪚蒚螛㮝閡㦦䞦䒩㮫皬鶮抲姀賀廅峆柇盇寉㷎䃒惒闔篕䫘䳚釛㿣㷤哬㓭秴䓼毼䳽㿥喛紇齃敆魺鲄䢔閤麧鵠䐧㰤㪃厒餄輅㰰㧁䶎鑉䓇欱轄㗿藃籺謞搤猲餲鉌齕佫覈暍鶡趷嗃挌渮犵") ("hei" "黑嘿|嗨||潶㱄黒") ("hen" "很狠恨痕|||詪鞎㯊䓳拫佷") ("heng" "行衡横恒亨哼珩|桁蘅绗黉姮鸻|堼|絎䄓䬖䬝㔰鴴鑅啈橫楻㶇澋撔悙誙䒛䯒揘諻恆烆胻脝佷狟") ("hong" "红宏洪轰虹鸿弘哄烘泓汞|訇蕻闳讧荭黉薨吽竑玒|纮翃唝浲硔谼|㗢㷎䬝澋撔娂紅訌䨎鈜霟焢䀧鬨䜫紭渱㬴輷渹鴻舼耾谾潂彋䡌呍晎䡏䩑葒葓䍔鍙轟硡鍧顭汯鉷䉺妅綋閎䞑㖓䆖宖玜粠䪦䲨䂫㢬垬㶹哅䧆揈篊黌䃔仜翝軣竤瓨苰峵䫹䫺叿嚝愩厷銾屸霐闂㧦巆紘谹魟浤灴鞃澒閧嗊鋐吰謍") ("hou" "后候厚侯猴喉吼|逅篌糇骺後鲎瘊堠齁|郈垕鲘|㸸腄䫺洉㬋㤧帿缿㕈䙈葔豞鱟㖃㺅䂉銗鮜㮢䞧䪷犼㗋䗔㫗䫛矦䳧翭詬䞀䡩㰯翵㰻鄇餱鍭睺鯸呴") ("hu" "和护许户核湖互乎呼胡戏忽虎沪糊壶葫狐蝴弧瑚浒鹄琥|扈唬滹惚祜囫斛鹘笏醐猢怙唿戽槲觳煳鹕冱瓠虍岵鹱烀轷縠|昒昈峘隺淴欻鄠嫭濩鳠|俿雽鶮㷤鍙焀萀簄鸌帍鬍嘑䠒弖鰗怘蔛嘝匢謢䨥㸦匫瀫㨭䔯蔰許戲戶頶䈸䨼䭅㕆䉉䭌䭍歑啒䍓乕恗絗歘楜虝婟摢䁫豰㹱魱䩴䕶護鍸汻䉿䊀垀䎁抇㺉枑綔喖鶘䚛嚛螜䪝媩熩㾰䞱冴䲵㪶箶䮸㦿䗂㗅䛎雐惖䇘泘㫚㯛寣軤㿥滬嫮淲瓳槴曶壷滸苸鳸壺䧼烼鱯嗀韄䩐縎鵠䵻䊺鶻淈㧽㽇㺀礐㴶㱿㦌㳷芐䤕鴩瓡嗃頀餬戯吰搰戸謼虖衚楛幠沍鶦膴臛芔擭鋘觷") ("hua" "化华划话花画滑哗豁骅桦|猾铧浍狯砉粿|婳觟鹢|魤䊐䴳䔯嬅䠉㠏舙㠢䔢嘩錵樺譁㩇㭉驊蕐㕦畫譮話㕲畵㕷杹䱻䅿劃澅㦊㚌㦎螖䶤澮㮯芲㟆磆䛡諣䏦鷨釫槬華㓰鏵竵䀨㼫䯏䇈腂䋀姡黊搳崋繣摦嫿咶檴罫鮭輠莋鋘釪") ("huai" "划怀坏淮徊槐|踝孬||㠢劃䴜瀤䈭耲㜳蘹蘾諙櫰竵䃶懷歠褢褱佪咶壊懐壞狥") ("huan" "还环换欢患缓唤焕幻痪桓寰涣宦垸|苋洹浣豢奂郇圜獾鲩脘鬟萑逭漶锾缳擐鹮|荁峘㬊貆澴嬛镮|䊐螌豩㢰䁵攌䁔䒛䠉㠢鰀鴅㬇萈愌輐䀓瘓渙阛䴟䈠䀨㼫酄嵈瑍鵍奐㕕㹖捖䝠歡煥䥧繯鍰㡲豲䭴㵹䍺㶎肒梙喚喛貛䮝䆠䦡瞣㦥羦環㪱嚾犿懁鯇雈㓉烉寏䯘藧觨緩㣪㿪糫槵䴷睔䄆絙鸛㔳巜孉䑏鉮綄䴉䴋欥蒝還鐶睆歓轘驩讙梡澣換瓛狟闤懽雚瞏蠸") ("huang" "黄荒煌皇凰慌晃潢谎惶簧璜恍幌湟蝗磺隍徨|遑肓篁鳇蟥癀|洸喤媓瑝滉锽艎|䄓楻揘諻篊汻䅿鐄鰉謊䌙朚騜䐠縨㨪餭愰崲䐵㤺㬻塃鱑穔奛䁜䑟葟鍠䅣兤詤䍿䪄䊗撗嚝㾠䊣皩趪㾮䮲墴㞷䞹宺曂軦䳨鷬晄櫎爌䵃䀮炾堭怳衁獚偟熀皝鎤榥熿黃巟韹") ("hui" "会回挥汇惠辉恢徽绘毁慧灰贿卉悔徊秽溃荟晖彗讳诲珲堕诙蕙|晦麾烩茴喙桧钺蛔洄浍虺恚蟪咴隳缋哕翚㧑|袆烠翙廆橞|䁤䢈䫖墮㺔䠉譮澮洃㜇䌇嬇瀈䜋阓蜖褘圚輝㨤㰥逥䤧蔧㬩㤬鐬頮匯餯鰴儶㨹琿鼿䕇䩈䙌婎䅏湏幑㩓潓譓噕饖彚䙡穢繢㥣噦噧靧㩨獩繪顪譭詯㑰潰㱱灳睳詴㑹詼譿媈禈薈暉㒑颒憓檓隓䂕嚖㞧殨誨禬鮰暳瞺叀毀㷄賄㻅毇泋㷐蛕囘櫘䛛僡韢䃣烣䧥䏨囬燬翬䫭寭揮藱諱燴䇻廻拻䛼廽䵻㽇㷇䎚䰎襘䍷檜鞼㫎䶐蘬瘣孈㣛蘳㾯嬒椲螝銊戯佪會褌嘒噅煇繐豗彙恛恵絵芔蚘撝璯濊痐滙闠槥篲迴鏸翽楎輠铓鉥薉徻鑴") ("hun" "婚混魂浑昏珲荤|馄诨溷阍|惛婫|䊐湷䐊㮯䮝觨琿堚餛焝䰟㨡倱鼲䴷渾繉轋顐睔䅙睧㑮敯䅱㥵祵葷䚠涽閽俒棔棞䫟諢䛰䧰忶鯶惽㨰輥䵪掍緄㯻䴹㕵緡㖧㗃眃梡濊圂餫昬慁楎睯殙梱焄") ("huo" "和活或货获火伙惑霍祸豁|嚯藿锪蠖钬耠镬鹱夥灬劐攉砉嚄|佸漷濩彟㸌鳠|鍃㶡䬉焃㕡咊䨥豰㯛㩇㚌㦎㓉䄀䄆礊謋䄑眓瀖㘞騞䰥鈥㨯耯萿靃捇楇鑊䉟彠艧䁨剨癨穫奯鱯獲䂄閄禍沎讗䦚㦜掝咟蒦貨邩㦯嚿嗀瓁韄矆㯉䯏矐臒旤曤䋭俰㗲秳䣶㨰趏䐸㖪姡秮䱛吙諕臛濊嗀湱檴雘擭矱咷篧") ("ji" "济机其技基记计系革期际及集级几给积极己纪即继击既激绩急奇吉季疾迹鸡剂辑籍寄挤骑圾冀亟寂暨脊跻荆肌稽忌饥祭缉棘矶汲畸姬秸藉瘠骥羁妓讥稷蓟悸嫉岌|叽伎鲫诘楫荠戟箕霁嵇觊麂畿玑笈犄芨唧帙屐髻戢佶偈笄跽蒺萁乩咭赍嵴虮掎脔齑殛鲚剞洎丌墼蕺彐芰哜罽伋|枅垍姞堲䓫徛鱾惎耤漈踦觭鹡穄蹐瀱|㱯魥㱦岋䆅䓧脨覘䈕姼茤䦈㑵䰥䩐䛋給瞉㨳䍯暩槣䐀紀褀㤂漃㸄鸄㨈計㴉刉簊㘍㠍樍㠎蘎騎䠏䰏刏焏礏尐䤒㔕㴕䐕萕㠖䨖鐖稘記䐚欚級䜞朞㰟䤠稩耭蘮輯嘰㠱愱霵鴶蘻霽績鬾鰿蕀襀㹄嵆㡇鑇塉穊鵋㥍積齍譏齏彑饑䁒湒筓鍓魕坖楖穖癘卙鑙轚㥛魝㱞魢䍤譤驥㑧㙨葪㙫繫㡭鱭㡮偮䩯㭰衱㭲極㡶彶橶䝸㽺聻繼卽兾妀䒁㞃撃㲅㞆䦇羈銈覉㾊斊薊覊鞊䢋誋躋嚌膌墍皍螏䚐钑㾒䶓檕䞘㞛際檝禝喞梞㮟撠㚡瞡銡㖢璣㞦㮨䶩㒫覬䲯嶯犱䢳㾵檵㦸躸㲺䮺薺亼璾箿㧀䗁曁䯂毄櫅諅郆槉㗊䟌㻑竒嗘觙裚鯚峜叝緝雞䋟僟濟擠跡䣢飢忣旣蟣揤狤雦雧賫䳭櫭擮臮鳮磯鯯㗱韲㳵鏶㻷賷懻蓻䓽鯽䁶憿㸅訐紒艥趌谻屰㞋鷑㓹䀈踑帺㞓䛴淁趞䀘鈘乁蠀吇㧗蒩簎䱥汥䇧皀畟茍欿蔇済瘈鈒踖霙丮鰶虀鱀塈繋襋齌蝍齎潗機蹟癠剤穧癪幾鮆羇斉莋鶏劑継禨隮庴鶺鞿鷄濈擊旡勣蛣泲痵苙錤鄿敧懠姫") ("jia" "家加价假佳架甲嘉贾驾嫁夹稼钾茄挟迦伽|颊浃枷戛荚痂镓笳珈岬胛嘏袈郏铪葭袷瘕铗跏蛱恝饸揳|泇浉叚斝跱槚|䇲鉿㔠㸦攪䢔賈鴶餃餄唊踋鴐戞㼪䀫頬頰䀹夾挾圿鉀捁㕅硈鵊䁍幏䕛䑝絞䩡乫鉫繳扴腵鉸浹婽鞂鞈宊犌貑㮖斚撟傢榢莢徦㪴鎵撹玾拁埉迌鋏㿓駕䛟郟毠嗧矯價蛺頡䘥忦抸筴仮耞猳椵舺豭榎麚梜檟価裌跲帢") ("jian" "建间件见坚检健监减简艰践兼鉴键渐柬剑尖肩舰荐箭浅剪俭碱茧奸歼斩拣捡煎贱溅槛涧笺|谏饯锏缄睑謇蹇腱菅翦戬毽笕犍硷鞯牮枧湔鲣囝裥踺搛缣鹣蒹谫僭戋趼楗谮鞬|钘靬暕篯鳒|㱯黬劗䞼袸䟢㽉㵎㹇㺂䭙聻礀㰄礆儉㔋鰎猏瀐踐縑蠒㔓䤔戔鰔礛騝簡鐧戩蔪樫䄯餰㨴稴㨵挸漸瀸倹鰹䬻瀽錽弿偂虃詃䩆襇䭈襉葌䉍䅐瑐魐鑒䭕湕䵖譖䵛籛䥜繝䭠䵡䵤艦筧鑬繭剱艱鍳鑳鵳鍵睷絸襺鹻譼鹼譾麉碊箋見劍劎劒銒間劔㶕㦗榗澗梘閚㺝趝熞侟䶠檢馢徤薦玪鎫殱殲覵覸螹檻瞼鶼䮿冿撿揀韀鋄䟅藆韉寋糋賎囏諓旔䧖緘䯛䇟䯡監㣤惤賤姦姧㳨鏩諫糮䟰釰䛳磵擶臶㓺㯺淺濺鋻櫼釼鳽跈䌠騫鐱㡨塹㪠黚䫡攕帴涀䶢瞯軒醶椾橏籈瑊朁鋑鈃堅洊鬋鐗減検鰜餞栫謭瀳椷堿牋蕑鑑豜剣豣鑯蕳幵鹸醎閒瞷熸揃廌珔俴菺葥傔揵僣轞") ("jiang" "将强江奖讲降疆蒋姜虹浆匠酱僵桨绛|缰犟豇礓洚茳糨耩丬膙|矼弶蔃鳉|䥒䜫瓨塂傋夅將講弜匞蔣強謽漿葁鱂䉃獎畕繦摪繮䁰絳䙹嵹畺摾螀䒂疅㢡醤䞪殭袶壃䋌㯍翞糡勥滰槳彊顜奨奬橿薑醬螿韁") ("jiao" "教交较校角觉叫脚缴胶轿郊焦窑骄浇椒礁佼蕉娇矫搅绞酵剿嚼饺窖跤蛟侥狡姣荞|皎茭峤菽铰醮鲛湫徼鹪僬噍艽挢敫藠|峧恔䴔滘斠漖皛燋璬皦皭|㿟㱶㩭䢪嬓樔虠悎稁攪餃踋捁絞繳鉸撟撹矯較嘄漅訆䀊嬌鐎㠐䠛䴛嘦䘨㬭茮鴵㰾㭂孂晈呌敎轎潐譑驕灚穚䥞譥湬㩰㽱㽲腳䁶敽芁䂃斆澆劋覐䪒嶕䆗暞嶠膠䚩鮫喬徺覺憿蟂烄㳅賋鷍曒䣤僥鷦勪臫鷮䡈䍊嵺䰘隦㹾嶣骹釥嫶䙼獥䕧憢敥䉰趭灂摷勦稾嘂儌挍鵁筊煍鱎噭蹻窌憍覚膲釂珓蟜蟭轇摎簥敿趫嘐詨") ("jie" "家结解价界接节届介阶街借杰洁截姐揭捷劫戒皆竭桔诫楷秸睫藉栉拮偕芥|阂诘碣嗟颉蚧锴孑婕疖桀讦疥偈羯袷喈卩鲒骱玠劼|岊㛃悈絜湝蜐僇耤鹖褯檞|栨嫅䦈㑵䞦䫘祴䘁紇騔㨰裓鍇㔚㸄㠍㠎尐㡇魝衱鞊䟌揤狤櫭㼪䀹䂃瀄㸅昅砎訐鐑紒䌖蠘蠞頡吤刦崨㨩搩稭丯洯㘶䀷㠹䰺堺脻刼㔾琾䔿䱄屆腉㝌畍㝏楐結啑嵑䁓潔蝔㑘䕙䥛鉣癤䅥嵥艥卪魪煯詰繲楶鍻偼鎅趌媎庎階㾏傑䂒岕犗媘䲙鮚鶛䂝㮞誡㦢徣躤㮮㞯誱䂶䲸喼巀節㿍痎滐擑䇒㓗䣠㓤觧菨䯰擳緳蓵擷飷䛺䗻迼袓疌蛶㫸衸妎斺雃諎艐毑謯㞏仮扢蝍蛣価椄踕㨗倢堦刧唶蠽魀楬幯榤莭掲犵袺緁脥姉") ("jin" "进金今近仅紧尽津斤禁锦劲晋谨筋巾浸襟靳瑾|烬缙钅矜觐堇馑荩噤廑妗槿赆衿卺浕|珒琎祲溍瑧瑨墐慬殣|笒䃡㻸䢻䉷䌍㴆䀆縉漌㬐䤐贐伒㬜䌝錦嬧唫䐶㨷㰹謹瘽䥆㱈晉饉㹏歏荕䭙䑤䝲鹶㝻齽嚍䖐䶖嶜劤㶦厪䆮覲㶳璶䒺勁僅濅黅緊惍藎埐凚鋟盡嫤䋮䗯㯲菳蓳䫴㯸僸巹燼㦗榗竻暜斳婜兓馸嬐䃸䤺釿枃堻臸儘紟搢進璡侭肵觔寖濜菫賮") ("jing" "经京精境竞景警竟井惊径静劲敬净镜睛晶颈荆兢靖泾憬鲸茎腈菁胫烃|阱旌晟粳靓痉陉箐儆迳婧肼刭弪獍璟|汫倞猄竫䴖璥麖鼱|晠頚頸粇䑤劤勁踁稉㬌䔔逕䜘脛瀞㘫弳剄荊㕋葏坕䡖坙婙聙靚婛鵛葝䵞汬桱㹵㵾鶁鶄涇妌宑徑經莖麠㢣誩亰梷傹憼旍㣏擏曔秔痙燛巠鏡竧淨鯨濪仱烴競竸蟼幜靘䝼坓鋞㸒頴丼浄経驚靜穽暻凈凊俓殑") ("jiong" "坷窘炯迥|垧炅冂扃颎|冏坰泂䌹䐃皛|臦臩昋逈蘏蘔㤯顈㑋煛幜澃冋綗䢛㢠㖥侰㓏僒㷗埛㷡囧駫烱䅃扄銄浻㯋褧絅煚熲駉") ("jiu" "就究九酒久救旧纠舅灸炙疚揪咎蹴韭|玖臼柩赳鸠鹫厩啾阄湫桕僦齑鬏氿|㠇|䠓䬨殧乣㼋㽱㝌倃舊舏匓匛萛紤丩鬮匶朻䡂㩆乆牞䅢慦齨㡱镹奺㲃䊆䆒麔䊘媨㺩㶭揂廄䳎廐觓䳔㧕䓘鯦鳩䛮韮鷲糺勼柾糾繆㙀剹㤹㥢杦稵樛捄轇㺵廏揫摎穋鉥") ("ju" "车局据具举且居剧巨聚距句拒俱柜菊拘炬桔惧矩鞠驹锯踞咀瞿枸掬沮|莒橘飓疽钜趄踽遽琚龃椐苣裾榘狙倨榉苴讵雎锔窭菹鞫犋屦醵焗蒟|岠坥弆岨泃珇帡秬砠竘崌娵筥腒鲏䴗澽|㡹㪯車俥㹼䎤㕢㯯櫃怐蓻勪䳔輂欅怇椇舉輋㘌䤎鄓䄔眗㜘踙昛蘜刟耟鴡焣㠪㬬䰬䈮䜯洰㘲愳鼳簴㨿㩀婅葅鉅絇㥌艍詎䅓䵕䡞䱟齟䱡㽤驧屨湨歫蹫䕮婮陱㩴鵴蝺㮂抅躆劇鮈檋鶋鮍㞐犑袓鮔䪕貗䶙趜冣箤䶥斪鶪㞫邭梮窶颶侷粷蚷䢹躹涺䆽痀䗇巈壉䃊狊諊駏駒跔姖淗據揟㳥凥泦鋦擧毩勮䛯䋰䣰䏱毱駶櫸鋸懼埾䀠爠螶忂㖩閰萭聥㵵蒩趉趡鉏処蹻椈匊踘挙怚蜛倶挶鐻楀鵙罝虡佢粔跙寠拠埧郹跼臄僪豦懅軥") ("juan" "卷捐圈眷娟倦绢隽镌涓鹃|鄄蠲狷睃锩桊|焆婘棬蜎|䐪鵍䄅錈餋鐫鬳䌸腃奆鵑䡓剶絹慻羂䚈㢧䖭劵鎸㪻㢾淃雋勌韏裐㯞埢姢菤䳪勬飬㷷瓹蔨呟絭闂梋埍鋗萒襈鋑儁圏朘帣脧睊睠罥獧捲悁臇巻屩弮巂鞙縳") ("jue" "决绝角觉脚掘崛诀獗抉爵嚼倔厥蕨|攫珏矍蹶谲镢嗟鳜噱桷柽噘撅堀橛孓蠼觖劂鞒爝玦|叕砄焆傕㵐潏燋玃|髉䍳虳㻡䈑䊽㔳鱖䳏㲄㭰踋腳覐覺䣤勪䤎㔃䠇鐍㰐爑氒刔欔㸕䀗挗䐘㤜鐝弡㔢訣崫逫欮焳爴谻䘿㭈䡈䍊鱊䝌譎彏孒捔絕橜㹟䙠屫㩱穱啳瑴䁷蹷決赽㭾亅䦆殌斍䆕蚗憠䆢龣嶥熦疦玨䞵芵䞷䖼䦼鞽䋉䏐㻕矡鷢䏣蟩㟲䇶㓸㷾䟾袦繑匷鶌誳闋闕泬妜趉䶂吷鴂嶡駃騤蹻覚鴃戄鈌瘚蕝屩絶钁貜撧躩憰趹臄蟨僪觼璚壆繘") ("jun" "军均俊君峻菌竣钧骏龟浚隽郡筠|蕈皲麇捃|囷莙珺晙焌葰畯䐃焞鲪|棞亀龜㤯㢠㖥雋䝌攈鈞攟蜠蔨㴫䜭頵呁䝍䕑陖鵘㕙㽙㝦汮㑺桾袀銁馂碅麏蚐㒞銞箟覠皸皹燇埈懏㻒寯姰㓴䇹駿鍕㼱鵔儁餕麕箘鮶軍濬") ("ka" "卡喀咖|咔咯佧胩||衉㮟擖鉲呿") ("kai" "开凯慨楷恺|揩锴铠忾垲剀锎蒈闿|炌|嵦濭䠽嘅㗆䫦㳀輆鐦䐩愷愾㡁鍇豈塏奒䁗剴䡷㲉炏䒓暟鎧勓闓烗凱㪡欯鎎幆侅愒欬開颽壒") ("kan" "看刊勘堪坎砍侃嵌槛瞰|阚龛戡凵莰丬|衎崁嵁墈磡|㵎㙳䖔闞䫲䳚䀍䘓㸝栞輡鬫轁偘歞塪龕冚䶫惂竷䁍䬻檻㪁輱欿歁顑轗矙埳穅扻") ("kang" "康抗扛慷炕亢糠|铛伉钪闶||忼摃䦎䲘砊㰠鈧漮鱇䡉嵻粇閌邟躿嫝鏮羫匟穅犺囥槺") ("kao" "考靠烤拷铐|栲尻犒|洘熇|㼥䎋稁䘓丂焅䐧鲓銬鮳槀鯌髛䯪燺嵪稾攷薧") ("ke" "可科克客刻课颗渴壳柯棵坷恪苛咳磕珂|稞瞌溘轲窠嗑疴蝌岢铪颏髁蚵缂氪骒哿钶锞剋牁|沄匼垎炣悈|錒濭㕎㼎㒆鉿頦䕣袔䫘毼磆礊䘁㝓䆟䗘錁䡷㲉堁礍騍娔樖愙礚㰤㤩萪鈳顆㕉䙐㵣兣敤牱㪃犐厒䶗醘㪙閜㪡碦㾧嶱課㞹㪼殼窼勀勊緙揢胢軻㥛㲺䁍嵑䋉㒞翗愘䯊硞䂺䓇艐趷歁尅渇搕砢簻嵙薖殻榼峇") ("ken" "肯垦恳啃|龈颀裉|珢硍龂|褃㸧錹豤齦肎肻墾懇貇頎齗掯") ("keng" "坑铿胫吭|铒|硁硍|鉺奟誙䡩娙挳坈鍞䡰摼妔劥銵鏗踁䀴揁阬硜硻牼殸") ("kong" "空控孔恐|倥崆箜|埪硿|錓㸜㤟鵼涳㑋鞚悾椌") ("kou" "口扣寇叩抠|佝蔻芤眍筘|竘|䁱㸸䧆㜌瞉䍍怐㔚㰯蔲敂㽛摳剾㲄瞘窛冦袧劶宼㓂鏂䳟釦滱䳹眗飡簆彄鷇茠") ("ku" "苦库哭酷裤枯窟|骷槁堀绔刳喾|矻绹圐|䊿泏䔯橭狜焅瘔褲㠸桍扝絝顝㒂庫鮬嚳趶郀俈跍胐秙䇢捁崫㗄硞楛袴窋") ("kua" "跨夸垮挎|胯侉髁锞|姱|袔恗楇䦚錁㡁顝㐄荂晇誇銙咵骻䋀䦱㛻") ("kuai" "会快块筷脍|蒯刽侩浍郐蒉狯呙哙㧟|鲙|澮㨤㻅廥檜巜㫎儈䈛㔞㬮欳鄶塊㙕㙗䭝獪㱮噲䶐墤膾䓒擓䯤糩㟴凷㕟蕢狤㭈㹟會璯旝咼鬠鱠喎駃") ("kuan" "款宽|髋||㮯䤭䕀歀䥗䲌髖臗㯘寬㱁梡欵窾寛") ("kuang" "况矿框狂旷眶匡筐|邝圹哐贶夼诳诓纩|洭|㾠軦䂄礦穬矌㫛㔞爌眖儣匩㤮鄺昿砿䵃硄彉絋㑌卝鵟筺躀誆纊誑䊯岲貺邼況俇黋軖壙曠懬懭軭忹丱恇絖鑛鉱抂劻迋") ("kui" "亏奎愧魁馈溃匮葵窥盔逵|睽馗聩喟夔篑岿喹揆隗傀暌跬蒉愦悝蝰|壸硊骙煃戣櫆|㾠嬇㤬䙌䙡潰㒑䇻㧉䏗㷇䰎䙆䁛㙺瞆膭䖯䯣胿㚍顝欳㱮㟴簀䤆謉䈐䠑㨒椢簣騩蘬蔮尯匱嘳蘷樻湀虁籄晆饋鑎楏楑㙓䕚蹞㕟蕢聧虧鍨䍪䕫聭聵鍷撌憒㚝躨犪䦱窺藈巋䯓巙䫥䳫䧶槶䟸㛻䠏㡭腃㰐䞚䫔闋䠿䃬噅鮭鐀鄈頍騤茥頯刲餽瞶鞹媿闚峞頄磈") ("kun" "困昆坤捆|琨锟鲲醌髡悃阃焜|壸堃裈婫鹍|㕎䐊餛祵鰥裩豤齦䠅稇崐崑猑錕蜫睏齫硱㩲瑻鵾涃貇綑閫閸惃髠鯤髨㫻罤鶤褌騉稛晜梱裍菎壼") ("kuo" "适扩括阔廓|栝蛞|漷|䩹䙃㣪䄆䄑㨯萿秳頢葀懖㪙㾧挄籗桰鞟䦢擃闊姡㗥䟯擴濶䯺噋筈髺鬠鞹霩適拡") ("la" "拉落垃腊啦辣蜡喇剌旯|砬邋瘌鞡镴|蝲|䀳㱞爉㸊攋蠟㕇楋蝋䝓䱫溂䪉䶛辢䂰嚹䏀柆臈菈㻋翋瓎䟑磖臘㻝藞䓥揦揧䃳䗶鯻癩儠㯿䏠搚㩉䖃䱨撦鬎鑞擸") ("lai" "来莱赖睐徕|籁涞赉濑癞崃铼|俫梾|䀳鵣誺勑㸊攋倈萊崍猍娕琜㠣䄤瀨逨䠭錸唻顂㥎䅘筙睞籟婡癩襰䚅來鶆㚓䲚徠㾢庲麳䂾䧒賚䋱郲櫴賴䓶棶淶孻騋瀬頼箂鯠藾") ("lan" "兰览蓝篮栏岚烂滥缆揽澜拦懒榄斓婪阑|褴廪罱谰镧漤|襕|坔㘕嚂㔋諫䈒䄤䲚䧒爁欄䰐㘓攔㰖儖欖欗爛爤爦㨫䌫爫蘫攬蘭㜮礷瀾䍀籃孄灆譋䑌孏嵐㩜灡㑣襤浨㱫鑭幱顲葻襽繿醂钄䪍斕讕䊖纜㦨䦨㞩厱璼覽䆾韊闌藍壏瓓㳕燗懢燣擥㛦懶燷糷䃹䳿漣僋蘭嬾灠籣襴躝覧壈囒濫惏湅") ("lang" "浪朗郎廊狼琅|榔螂阆锒莨啷蒗稂|俍埌崀悢桹㫰烺蓢筤塱㮾|䃹樃朖朤欴䀶䁁艆㝗䡙䍚䕞㙟硠㱢瑯䱶㢃斏誏㾗䆡閬躴㾿鋃勆蓈㟍峎嫏郒䯖㓪脼哴駺鎯樠蜋郞") ("lao" "老劳落络牢捞涝烙姥佬崂唠|酪潦栎痨醪獠铑铹栳耢|荖嫪橑|䜎鐒㨓簩嘮耮䝁恅癆䵏絡䝤䕩橯浶澇撈䲏嶗㞠銠憥憦軂㟉䳓䃕僗㟙髝勞㗦蟧䇭㧯磱㟹䜮顟㺐老轑窂労咾狫哰嘐") ("le" "了乐勒肋|叻鳓嘞仂泐饹|簕|㨋㿭牞樂餎頱鰳㔹氻㖀玏㦡忇哷韷竻阞砳扐艻楽") ("lei" "类累雷勒泪蕾垒磊擂漯镭肋|羸耒儡嫘埒缧酹嘞诔檑|藟礌癗罍|㵽腂㲺㗊㰐㻋郲攂㴃㼍䴎錑䨓頛蠝洡㔣瘣礨頪䐯蘱縲蘲鐳鼺蘽靁䉂灅蕌㑍㹎䉓鑘㡞類轠㵢䍣䍥㭩䉪鑸㙼誄讄銇㒍䮑㲕纝㶟颣㒦䢮禷䒹厽䣂瓃囄櫐櫑㿔壘淚䣦壨䛶㠥祱䃬樏鸓欙礧儽塁虆絫畾纇纍涙傫磥蔂") ("leng" "冷梭愣棱楞|塄崚|堎|䬋倰䉄䚏䮚輘㱥碐蔆稜踜薐睖") ("li" "理力利立里李历例离励礼丽黎璃厉厘粒莉梨隶栗荔沥犁漓哩狸藜罹篱鲤砺吏澧俐骊溧砾|莅锂笠蠡蛎痢雳镉俪嶙傈叻醴栎郦俚枥喱逦娌鹂戾砬唳坜疠蜊黧猁鬲粝蓠呖跞疬酾刂缡鲡鳢嫠詈悝苈篥轹棁朸|叕峛珕浬浰凓漦醨釐㰀|銐麶黐荲扚蒚䕻鎘㷴兣欚癘䗶㠣㥎㴃錑䍥囄䚏䔁氂䴄爄䬅錅䔆䬆樆蠇䘈䔉攊琍㔏㬏爏㘑刕㼖茘䤙㰚㸚䤚蘚䰛栛䄜䰜㴝瀝㠟㤡䴡攡䔣蠣㤦攦䔧蜧謧礪礫蠫攭縭儮搮礰娳儷脷騹蘺䴻㽁㡂靂䡃艃䅄慄㹈酈孋靋䵓剓鑗䱘塛㽝睝鉝䍠轢筣轣㑦䍦癧鱧䵩驪䉫籬瑮婯䙰鱱穲赲鱳䥶孷蝷㕸㱹鵹鱺䁻䅻䍽犂纅讈䮋邌䊍粍㾐邐㦒躒䚕㾖涖麗䶘㮚粚麜䲞蒞嚟綟㺡悡犡䖥䮥嚦岦㒧悧䊪檪禮厯厲禲粴沵悷梸蚸隸䖽㒿䖿巁棃釃瓅鷅曆囇瓈䧉鯉矋䗍蟍㻎糎䟏䇐䟐瓑鷑䣓櫔棙釙㗚㿛秝䓞曞菞櫟盠蛠壢峢離㯤䋥瓥㿨鳨櫪䣫鋫鏫鯬㓯䃯㧰㷰鋰峲廲㟳雴勵藶蟸㻺觻濿磿颯叓矖豊儗扐鬁栃砅唎欐鴗鸝栵褵蔾灕屴歴歷剺斄貍劙犛厤暦梩皪沴隷裏苙裡盭糲擽戻纚杝柂") ("lia" "俩|||倆") ("lian" "联连练廉炼脸莲恋链帘怜涟敛琏|镰濂楝鲢殓潋裢裣臁膦奁莶蠊娈蔹梿|浰瑓磏|䐄稴輦戀㜃㰈鰊㼑㼓㜕嬚堜蘝䌞蘞漣連䨬鐮萰謰鰱匲瀲匳褳㰸縺㜻煉孌䭑噒㥕㡘襝䁠籢䥥蹥譧㱨籨聨奩慩聫聮奱㝺䙺㦁䆂斂劆璉螊㶌憐㦑㶑熑薕㢘㪘㪝覝纞薟媡㺦殮亷羷㾾㟀僆䏈鏈㓎濓䃛䇜櫣槤燫㯬蓮練翴嫾槏醶憰鬑錬鄻簾湅鍊摙歛聯鎌溓練澰臉嗹鱄") ("liang" "量两粮良辆亮梁凉俩谅粱晾|靓踉阆莨椋魉墚|俍倞悢辌|靚䀶䁁㾗閬倆䠃輌樑簗輛㔝唡脼蜽㹁鍄魎䭪䩫䝶湸掚綡㒳緉諒䓣糧哴駺䣼両輬啢兩喨涼裲刓媟") ("liao" "了料疗辽廖聊寥僚燎缭撂撩|嘹潦镣寮蓼獠钌尥鹩瞭蹽|漻憭嫽簝髎|䣈繆䕞㨓䝤㞠蟧㜃䨅䜍鐐爒鄝尞䄦尦䜮䝀療豂㝋䩍蹘繚顟䑠䍡㙩㵳嵺㡻䉼遼镽䎆㺒炓璙嶚嶛䢧㶫熮窲窷蟉飉釕鷚蟟廫鷯賿窌轑摎屪敹憀膋膫暸飂鏐") ("lie" "列烈劣裂猎冽|咧趔洌鬣埒捩躐|䴕脟|䋑獦爉㸊䝓䪉䶛䃳哷㭩爄䬅㤡䮋綟巁棙㻺挒鬛㤠儠㬯㼲䜲㸹䅀浖聗㭞㽟䉭煭鱲獵䁽犣鮤㲱颲劽埓㧜䓟巤䟩姴蛶䟹迾㯿燤忚奊栵猟茢鴷睙蛚擸劦") ("lin" "林临邻赁琳磷淋麟霖鳞凛拎遴蔺吝粼|嶙躏廪檩啉辚膦瞵懔璘|箖潾翷|癝㖼玪顲䚏㔂㨆崊甐焛㐭鄰瀶橉驎轔繗鱗癛㝝恡轥罧䉮䕲蹸晽㖁檁疄碄悋躙撛綝澟粦躪䚬䢯斴閵厸䮼暽賃懍䫐凜矝㷠壣臨廩䫰䗲痳藺魿㡘㝺䢧䟹獜亃麐隣惏燐僯菻鏻溓") ("ling" "领令另零灵龄陵岭凌玲铃菱棱伶拎羚苓聆翎泠|瓴囹绫呤棂蛉酃鲮柃祾|坽姈昤鸰堎舲㥄澪|㭩倰䮚靇錂䴇䈊琌朎䴒䔖霗輘領霛欞㬡䌢刢䄥蘦爧䨩䴫䰱砱䠲㸳鈴紷阾䉁孁䍅婈靈衑䉖䕘齡㱥䙥㡵蕶鹷䉹䡼彾䡿魿䖅㲆㾉皊袊碐掕䚖龗閝麢炩㖫㦭㪮岺嶺綾跉䯍㻏狑駖䧙竛秢㯪鯪裬燯櫺蔆稜〇霊夌鴒霝笭詅睖齢呬醽軨淩") ("liu" "流刘六留陆柳瘤硫泵溜碌浏榴琉馏|铆遛鎏骝绺硐镏旒熘蒌鹨锍镠|珋飗罶鹠瑬疁|䒥㳅㧕㚹䉹䝀㝋㵳熮蟉鷚栁䄂鐂瀏䰘䬟鰡㨨㐬騮鬸嬼餾㙀畂畄癅橊㽌驑䱖鉚㽞䱞瑠䉧嵧橮塯畱䭷桺羀䶉劉麍澑嚠沠璢蒥鎦䚧㶯媹綹磂蓅飅廇旈鷎裗䗜駠雡藰駵鋶䋷飹窌摎飂霤蹓坴陸鶹飀翏鏐懰磟") ("lo" "|咯||") ("long" "龙隆弄垄笼拢聋陇胧珑窿|茏咙砻垅泷栊癃挦眬|昽哢祲漋|谾簼㳥挊㰍攏爖鸗贚蘢朧瀧蠪蠬礱㴳霳挵䡁豅靇㙙㑝籠驡䥢㡣硦鑨䙪㝫湰襱屸聾㚅㢅梇䪊䆍龍嶐龒龓㦕嚨隴徿巄竉䏊瓏矓㟖㛞槞壟壠䃧鏧曨篭櫳䰱䮾蕯篢儱礲衖躘巃竜滝捰") ("lou" "楼露漏陋娄搂篓|喽镂偻瘘髅耧蝼嵝蒌窭䁖|剅溇|㡞甊嘍簍樓䄛蔞耬謱㔷瘻婁䝏屚艛摟㥪遱䅹䱾嶁㲎㺏瞜熡䮫㪹螻鞻軁僂髏廔䣚鷜鏤䫫㟺慺寠漊瘺塿") ("lu" "路六陆录绿露鲁卢炉鹿禄赂芦庐碌麓颅泸卤潞鹭辘虏璐|漉噜闾戮鲈掳橹轳逯渌蓼撸鸬栌氇胪镥簏舻辂垆箓甪|垏菉琭稑僇勠澛蕗|賁璷繆㪹鱳觻䍡䐂椂瀂錄輅蘆氌蔍攎樐爐䌒䰕鸕瀘㜙樚踛㠠圥蠦鈩㔪䴪鐪舮錴䘵簶騼娽㼾虂轆硉䡎㭔蹗籙䱚䡜虜摝䕡轤鑥鵦睩艪艫䩮顱鵱魲硵鹵塶塷鱸剹獹㱺祿䚄㦇䮉㪐䲐䎑侓膔嚕㪖㢚熝趢枦嚧㖨㪭螰㢳粶䎼鏀賂擄峍勎㓐瓐矑櫓淕鏕㿖髗廘䃙壚臚㯝㯟㟤曥淥盧櫨㛬廬㯭觮鏴滷黸鷺擼㫽蓾䟿䥨櫚坴陸翏騄簬録盧穋罏彔籚艣鑪魯醁玈纑盝磟磠鯥緑") ("luan" "乱卵滦峦鸾栾|銮挛孪脔娈|脟|䚕㼑㰸孌奱䏈䜌欒圝鸞攣㝈鵉虊㱍灓灤㡩癴癵鑾孿䖂亂羉薍巒臠釠曫覶臡圞乿") ("lun" "论轮伦仑纶沦|抡囵||睔㕢綸䈁圇稐崘崙踚耣蜦輪倫腀婨陯䑳掄侖碖溣㖮惀棆㷍菕論埨鯩淪錀") ("luo" "落罗络洛逻螺锣骆萝裸漯烙摞铬骡|咯箩珞捋荦硌雒椤橐镙跞瘰泺猓脶袼猡倮蠃啰|蓏|槖䎅㮝䉿鉻㪾蛒腡䴹䙨㕵㞅㵣㾧絡䃕頱㖀䉓䮑硦㔏攭鱳躒㾖䲞䗍㸹攎䈁㰁鸁㼈欏㴖洜䀩䌱䌴䈷鴼騾笿蘿鵅剆㽋驘饠㩡㑩籮癳㱻鑼玀邏犖鮥䊨㒩㦬鎯覶躶覼䯁峈鏍䇔㿚嗠㓢曪駱濼渃䎊覙詻砢皪蔂攞儸羅纙囉臝捰") ("lv" "率律旅绿虑履吕铝屡氯缕滤侣驴榈|闾偻褛瘘捋嵝膂稆|垏梠菉葎溇|哷㡞謱瘻婁䝏䮫軁僂䣚鷜䕡䮉㢳氀爈挔䔞儢㠥㔧縷褸呂㭚捛穞屢驢祣䥨慮慺絽膐㾔䢖綠膢閭㲶侶箻馿鋁櫖郘櫚㻲勴濾寽繂寠漊録魯嵂卛鑢穭膟緑藘") ("lve" "略缕掠|锊|䂮圙|㗉攊䤚㔀䌎䤣稤㨼畧㑼䛚鋝鋢寽詻擽") ("ma" "么马吗摩麻码妈玛嘛骂抹蚂|唛蟆犸杩嬷麽孖|祃|䠋䀣䠨䧞㕰帓尛嘜鰢嬤㜫蔴㐷㨸獁瑪睰罵㑻閁㦄犘螞禡榪鎷㾺碼媽蟇鷌嗎䣕䣖䯦䗫擵䳸䀛鬕驀礣亇傌溤馬麼駡痲俛") ("mai" "买卖麦迈脉埋|霾荬劢|骍|㦟䳸脈䘑䜕霡㜥䨪嘪䨫㼮䈿眿佅蝐蕒䁲邁䚑麥䮮買賣勱鷶衇薶売霢貍") ("man" "满慢曼漫埋蔓瞒蛮鳗馒|幔谩螨熳缦镘颟墁鞔嫚|鬘|䒥䨫蔄㬅䰋䜱縵蠻鰻䐽謾饅獌襔䕕㵘䝡㙢㡢䝢顢蹣䡬䑱摱慲䅼悗瞞䊡澷㒼䟂㗄㗈僈鏋蟎矕鏝㛧䛲䯶滿姏睌㿸鄤鬗屘満璊澫槾樠絻") ("mang" "忙盲茫芒萌氓莽|蟒邙硭漭牤|杧尨牻|奀㵃䓼朚笀吂鼆蘉䈍蠎娏㬒䀮茻㙁㝑䅒汒㡛浝硥䵨䁳恾䒎䖟莾㻊㟌㟐蛖痝䟥釯盳狵壾㟿䏵䙪㜃㤶㴇杗庬铓哤鋩駹鸏") ("mao" "贸毛矛冒貌茂茅帽猫髦锚懋袤牦|卯铆耄峁瑁蟊茆蝥旄泖昴瞀芼眊|鄚楙疐|貇蝐㬒㴘䀤堥錨渵笷萺㡌艒酕䡚罞㝟䅦冃枆媌冐瞐覒暓貓㮘鶜㪞㲠㒵㚹㺺㒻貿䋃㧇䫉㧌柕㿞軞䓮㫯嫹霿愗緢毣氂㹈䖥鉚䭷嵍蓩秏夘鄮戼兞皃冇媢髳毷鉾犛") ("me" "么|麽||濹尛麼嚜") ("mei" "美没每煤梅媒枚妹眉魅霉谜昧媚玫酶镁湄寐莓袂楣|糜嵋瑁镅浼猸鹛郿|渼媄瑂溦|䞼䆊羙䀜㜫㙁㡌䤂栂脄嬍謎攗䀛䰨䰪挴䜸鬽睂嵄呅湈䉋㭑䍙祙蝞䵢楳睸塺葿䆀鎂鎇䊈䊊沒鶥㶬㺳䒽徾凂篃跊槑燘黣䓺珻抺䱕蘪櫗娒氼矀坆膴眛脢堳腜煝禖沬媺鋂毎韎痗黴苺穈") ("men" "们门闷|扪焖懑鞔钔|亹|㙢悗㻊們㨺㥃鍆㡈虋㵍䝧㱪捫門閅㦖䊟暪悶䫒菛燜懣怋䪸玧殙璊樠穈") ("meng" "蒙盟梦猛孟萌氓朦苎锰檬|勐懵蟒蜢虻黾蠓艨甍艋瞢礞獴|尨㠓幪鹲|䁅顭䁫朚㽇䝢鼆蘉䈍䖟㻊䟥䀄氋䴌䰒䤓儚萠䠢夢夣霥鄳錳㜴鄸䴿霿靀䥂䑃蕄䑅䵆橗㩚䉚饛䙦䙩䥰㝱蝱㙹䒐溕䲛㚞冡䇇矇䗈鯍矒懜䓝懞鯭䏵雺瓾嫇鱦庬鋂鸏甿莔曚濛") ("mi" "米密秘迷弥蜜谜觅靡泌眯麋猕谧咪|糜宓汨醚嘧弭脒纟冖幂祢縻蘼芈糸敉|狝洣祕醾|䋳㘠䀣㵥䣥䉲䊫㦄䈿謎㨺覛熐戂㜆䤉䤍鸍㸏䌏䌐謐樒㸓䌕䌘簚蔝漞㨠攠蠠䴢爢蔤㠧䌩蘪眫瀰渳㴵㜷㰽䁇䱊孊㵋籋彌幎灖䍘罙㥝葞㩢㝥䭧䭩䕳䕷䥸詸獼䉾镾瞇麊羋侎䖑榓覓覔冪䮭䊳檷宻䪾蒾醿櫁釄㣆䛉藌䛑瓕濗㫘峚䋛㟜擟䛧淧㳴滵㳽䣾淿䈼鑖沵摵瞴䖹鼏塓幦羃麛冞銤禰濔沕") ("mian" "面棉免绵缅勉眠冕娩|腼渑湎沔黾宀眄丏|勔偭愐|牑㝃㐷䯶㨺㡈緡䌏蠠㥝䛉㫘㤁㰃䤄㬆䀎㴐䰓嬵婂汅蝒靣㝰芇㮌媔喕㒙澠麪粫麫莬檰麵麺綿䏃糆䃇矈矊櫋矏緬㛯㻰臱䫵黽厸䩄葂靦絻鮸俛緜") ("miao" "苗秒妙描庙瞄缪渺淼|藐缈邈鹋杪眇喵||㷅䏚仯媌㠺繆鱙㑤䁧䅺鶓㦝䖢庿篎竗廟緢緲彯訬玅") ("mie" "灭蔑|篾乜咩蠛||眜䌩㩢羋吀䘊瀎鴓搣礣䈼䩏鑖孭鱴䁾薎覕㒝滅烕櫗懱哶衊幭") ("min" "民敏闽闵皿泯|岷悯渑珉抿黾缗玟愍苠鳘旻|忞盷湣碈|簢䶔㞴湏敯惽䞀䝧砇㨉錉怋崏琘笢鈱鰵䡅瑉䡑䁕慜潣捪鍲㥸䡻䲄閔閖䂥閩憫㢯㞶䪸冺勄姄䃉䋋緍忟緡䟨㟩㟭賯僶盿蠠㬆㮌澠黽厸渂鴖㳷刡敃罠暋閺痻旼呡") ("ming" "明名命鸣铭冥茗|溟酩瞑螟暝|洺蓂|䳟眀䄙朙眳猽慏㝠佲詺䊅䒌熐銘䆨䆩覭嫇凕䫤㫥㟰姳鳴䤉䏃鄍榠") ("miu" "缪谬|||繆唒謬嘐") ("mo" "万无没么模末冒莫摩墨默磨摸漠脉膜魔沫陌抹寞蘑摹蓦馍茉嘿谟|幺秣貉嫫镆殁耱嬷麽瘼貊貘靺|鄚藦|絔狢貈㠢㵹䳟帓尛嘜㾺擵脈䘑㜥眿艒冐瞐沒㶬䘃爅䜆鬕眜帞砞無謨昩謩萬䴲礳䬴縸圽驀饃㱄䱅橅衇絈䩋獏湐䉑慔饝魩㹮㱳塻䁼䁿歿貃庅銆鞆莈皌粖瞙覛嚤嚩䒬䮬暯劰嚰袹抺枺鏌髍蟔䏞懡䯢蛨㷬䳮㷵䃺嗼嫼戂䤉䌕攠䭩䊳瀎譕麼霢眽歾纆劘嚜妺麿黙糢灑") ("mou" "某谋牟缪眸|哞蝥鍪蛑侔呣||㖼䦈㼋䜼堥䍙謀踇愗洠鴾恈㭌䥐䍒䱕桙劺䗋䏬蟱繆鞪䋷敄瞴冇鉾麰") ("mu" "目模木亩幕母牧穆姆墓慕牟牡募睦沐暮拇姥鹜|钼苜仫毪坶||㟂朷䮸㫛茻㙁萺艒縸橅獏慔䁼踇繆氁㜈娒樢砪䀲畆䥈畒畝畞鉧鉬畮䱯䑵㒇㾇炑蚞鞪莯墲䊾㧅狇㣎䧔峔胟毣雮霂楘幙牳鶩拏") ("na" "南那纳拿哪娜钠呐捺|衲镎肭|乸|秅㧱㭯䞕貀㙁鈉納䀑笝訤㨥訥䈫㴸䅞魶䱹靹豽䎎䪏抐䖓妠袦䖧蒳誽鎿䛔㗙䟜䇣䏧雫䇱䫱嗱㮏詉蒘蹃郍䋈㪎㵊笚䋾挐吶拏軜淰") ("nai" "乃奶耐奈|鼐萘氖柰佴艿|迺耏|㜨㚷腉㜷䅞䘅倷渿摨䍲㮈熋㾍㮏疓㲡釢䯮廼䱞掜搱氝褦嬭錼孻螚妳") ("nan" "南难男楠喃|囡罱赧腩囝蝻|萳婻|嫨㬮妠䈒娚䔜䔳㽖畘䁪湳奻䕼枏枬莮䶲侽䛁揇㓓難㫱䊖䣸䩅戁暔柟諵") ("nang" "囊|馕囔曩攮齉||涳擃欜儾饢乪㒄䂇㶞嚢憹鬞䁸譨㚂搑灢蠰") ("nao" "脑闹恼挠瑙|淖孬垴铙桡呶硇猱蛲|峱臑|㧘碙巙䙹憹䜀䴃鐃夒怓堖匘䜧鬧䄩橈詉䑋㑎腦獶繷獿㺀㺁撓閙嶩㞪碯巎嫐髐䛝䃩蟯惱㛴䫸㺒蝚腝䐉婥脳譊悩摎") ("ne" "呢哪呐讷|疒||眲䭚訥䅞抐䭆䎪㕯吶") ("nei" "内那哪馁|||㐻䜆䇣㨅㼏餒㘨脮腇㕯䡾䲎㖏鮾䳖鯘娞錗氝內婑浽") ("nen" "嫩|恁|媆臑|㒄㜛㶧黁㯎腝嫰") ("neng" "能|||䪏䘅㴰㲌薴濘䏻螚儜竜") ("ng" "|嗯唔唵||㕶㐻") ("ni" "你尼呢泥拟逆倪妮腻匿霓溺|旎昵坭铌鲵伲怩睨祢疒猊慝|鹝鹢薿麑|懝兒䮘㧱聻㮞檷䀑抐誽䍲㮏㲡䘌縌㠜儞䘦鈮䰯伱愵嬺氼䘽䵑䵒屔婗䝚䁥䕥孨㵫屰䭲孴㹸譺㥾籾㦐㪒馜隬蚭抳䦵㲻㞾痆㣇䧇狋䛏胒鯓狔秜跜嫟迡鯢淣苨擬觬埿鑈棿腝蛪㘈眤㩘晲掜禰妳堄儗輗蜺鉨齯鶂貎膩暱惄柅鷊臡郳衵") ("nian" "年念粘辗碾廿|捻撵拈蔫鲶埝鲇辇黏||䟢㮟䧔痆攆簐㘝輦䄭䬯鼰䄹艌䩞蹨㞋躎鮎䚓撚㲽跈秊秥姩鯰㜤䴴輾蹍榐唸卄齞涊淰溓") ("niang" "娘酿|||孃䖆釀嬢醸") ("niao" "鸟尿溺袅|脲氽茑嬲鸮||㼭茮樢䐁㠡蔦褭㜵䙚㭤䦊䮍㞙㒟裊鳥㳮䃵嬝嫋枿") ("nie" "摄聂捏涅镍|孽坭蘖啮蹑嗫臬镊颞乜陧|菍嵲糵|㟧㖕䞕峊㜦䜆籋䇣㘨䡾㖏䳖痆㘝踂帇㸎䄒䜓踗䌜錜鈢蠥㴪㜸圼㘿鑈噛㙞鉩㡪顳㩶聶鑷孼钀㮆隉疌㚔㖖嚙躡鎳䂼䯀囁䯅揑巕惗擜篞櫱䯵棿䭃䌰諗褹掜槷囐鋷讘銸嶭蘗摰鉨摂敜齧湼枿闑囓糱臲苶喦") ("nin" "您|恁||㤛䚾䛘囜拰䋻") ("ning" "宁凝拧泞柠|咛坭狞佞聍甯|苧|䆨薴濘鸋鬡嬣䔭鑏㝕䭢橣獰聹嚀侫㲰檸矃寍寕寗寜㿦寧擰㣷䗿㩶鬤儜") ("niu" "牛纽扭钮|拗妞蚴忸狃杻||䮗抝牜莥䤔㽱䂇怓紐䀔鈕靵汼炄䒜㺲䏔䋴衂沑㖻") ("nong" "农浓弄脓侬|哝秾||㺜莀䂇憹繷欁儂鬞癑䵜噥䁸蕽檂䢉禯辳㶶膿濃挊挵齈襛穠農醲") ("nou" "|耨|嬬|檽䫖㕢䔈㜌㳶鐞䘫䰭䨲啂譨譳䅶㝹羺槈嗕搙獳鎒") ("nu" "努怒汝奴弩|驽帑呶孥胬|砮笯傉媆|䢪詉黁搙伮蒘䢞㚢駑㣽") ("nuan" "暖||臑|奻㬉渜愞䙇煗䎡湪餪煖") ("nuo" "诺挪娜糯|懦傩喏搦锘砹||䎟䎠㖠袳毭搙愞砈㰙㐡稬㔮儺搻挼逽蹃㡅㑚橠穤鍩榒梛䚥㛂郍糑糥懧䇔捼掿諾媠袲") ("nv" "女|钕忸衄恧||聏㮟䏔䘐朒衂㵖䶊䖡䚼釹沑籹") ("nve" "虐疟|谑||婩䨋謔瘧硸䖈䖋") ("o" "哦|噢喔嚄||") ("ou" "区欧偶殴呕藕讴鸥瓯|沤耦怄吽||䌂甌䌔嘔吘漚謳㼴㸸蕅歐湡腢慪塸䚆膒㒖毆㛏鷗櫙䯚蓲鏂㭝藲㰶紆醧鴎區熰齵") ("pa" "怕帕爬扒趴琶啪葩|耙杷钯筢|蚆舥潖|鈀㞎䎬䎱苩汃㕷帊皅妑䶕袙䯲歠掱跁") ("pai" "牌排派拍迫徘湃|俳哌蒎|椑簰|䮘䱝䃻矲箄㵒猅輫簲汖㭛㵺鎃䖰俖篺犤棑廹") ("pan" "判盘番潘攀盼拚畔胖叛扳蹒磐|爿蟠泮袢襻丬柈|槃磻|褩㩯螌賁䙃䩔畨緐䋣㵗蹣眫䙪䰉瀊䰔砙搫䈲㐴牉坢奤鑻炍沜鎜蒰冸溿䃑跘盤㳪鋬䃲䏒乑洀籓頄眅縏頖踫詊幋鞶媻") ("pang" "旁庞乓膀胖磅螃|彷滂逄蒡耪雱|尨厖鳑|鎊髈䠙鰟㑂汸趽㝑䂇㜊䨦騯㤶霶舽㥬䅭䒍龎厐炐龐膖沗肨覫䮾㫄嫎篣胮㕩夆庬徬嗙") ("pao" "跑炮泡抛刨袍|咆疱庖狍匏龅脬摽|脟|袌㲏鮑嚗蚫䠙謈颮㯱㘐礟爮礮奅䩝靤麅垉䶌麭皰㚿拋䛌瓟㯡髱軳犥麃窌砲鞄炰") ("pei" "配培赔佩陪沛裴胚|碚霈旆帔呸醅辔锫|荖垺衃|笩䂜㾦㯁䟺㸬嶏犻䫊柭䕗䩛㚰㨐䏽䡊錇翇䯱攈㣆俖伂㤄娝昢琣阫轡陫浿䊃妚肧岯馷䪹䲹斾㳈䣙㟝苝䫠賠㧩毰㫲姵裵駍婄怌抷茷珮柸") ("pen" "喷盆|湓||㾦衯㖹葐噴喯翉瓫翸濆歕呠") ("peng" "鹏朋彭膨蓬碰棚捧烹篷澎抨硼|怦砰嘭蟛堋椪芃|泙荓淜弸搒|㔙挷㮄䧛逬㑟㱶熢槰䋽䵄漨摓莑剻㮟騯篣㘐䣙䰃錋鬔椖倗䄘稝㼞輣樥䴶㥊硑塜鑝䡫鵬恲塳纄梈憉皏閛亯傰埄駍淎㛔蟚磞軯韸竼韼髼輧胓絣踫鬅匉漰掽痭") ("pi" "批否皮辟啤匹披疲僻毗坯脾譬劈媲屁琵邳裨痞癖|陂丕枇噼霹吡纰砒铍淠郫埤濞秕睥苤芘蚍圮鼙罴蜱疋貔仳庀擗甓陴玭苉|伾沘狉椑鲏澼䴙嚭|㼰罷䇑䴽伓䡶藣㱟疈嶏蚾鵧朇稫㡙㵨魮悂枈䪐螕䖩㮰闢羆鈈䤵㽬䗄䯱鈲鮍㔃䦼篺㳪妚岯䪹䲹䫠鸊怌錍䤏渒笓礔礕紕䠘耚鈚㔥崥䰦䤨蠯阰脴怶焷鈹㨽䑀䑄腗䡟鉟睤豼噽豾魾嚊炋膍銔犤隦䚰憵肶抷螷䚹蚽壀諀㯅旇磇揊䫌翍嫓䏘㿙秛毞髬釽鷿奊銢猈鞞鎞壊壞鴄潎狓駓毘秠髲") ("pian" "便片篇偏骗匾翩扁堑|骈胼蹁谝犏缏|萹㛹楩|跰鶣猵楄獱緶騈㼐騗騙㸤頨腁䮁覑媥貵骿賆䏒諚諞駢囨㓲璸") ("piao" "票朴漂飘嫖瓢|剽缥殍瞟骠嘌髟莩螵摽|蔈薸|㲏謤驃徱㯱淲鷅㬓䴩縹㼼魒慓㩠顠䕯彯㵱㹾㺓犥醥竂飃䏇旚闝勡翲篻驫麃僄潎皫飄") ("pie" "瞥撇|苤氕丿||嫳覕鐅䥕撆暼潎") ("pin" "品贫聘频拼拚泵|颦姘嫔榀牝玭|涄|㲏瀕驞穦馪矉琕獱㻞砏汖㰋蘋礗娦朩嬪䀻頻顰貧薲蠙嚬") ("ping" "平评凭瓶冯屏萍苹乒坪|枰娉俜鲆堋|泙玶荓帡洴涄蚲淜|㲏䈂䓑檘馮㵗倗硑蘋䀻甁簈輧焩頩砯帲甹䍈幈評屛聠呯艵慿鮃䶄憑覮箳㺸炾㻂胓蛢竮蓱郱凴絣鉼缾軿") ("po" "破繁坡迫颇朴泊婆泼魄粕鄱珀|陂叵笸泺皤钋钷|桲酦皛馞|䮘㧊㩯謈猼敀䍨岥駊㤕䦌醗醱緐䋣㜑䘠䎅䪙屰釙搫昢尀㨇頗嘙蔢洦䨰㰴砶䄸潑鉕癹炇䎊溌䪖䞟蒪岶櫇㛘䯙烞䣪䣮鏺翍尃巿廹") ("pou" "剖|掊瓿锫裒抔|垺棓|堷㼜䎧䳝錇䯽娝㟝㰴吥婄捊㕻犃咅抙廍哣㧵㩠箁") ("pu" "普暴铺浦朴堡葡谱埔扑仆蒲曝瀑溥莆圃璞濮菩脯|蹼匍噗氆攵镨攴镤|蒱酺墣潽穙|㙸䪬獛荹豧秿釙䴆圑䔕舖鐠圤㬥䈬䈻轐䑑㹒譜陠襥纀箁檏㒒䲕暜瞨㺪抪㲫撲擈僕䧤柨諩鋪䗱㯷鏷駇捗蜅鯆舗樸襆誧菐痡烳") ("qi" "企其起期气七器汽奇齐启旗棋妻弃歧欺骑契迄亟漆戚岂稽岐琦栖缉琪泣乞砌祁崎绮祺蹊祈凄淇杞脐麒圻憩芪|俟畦荠箕耆葺沏萋骐鳍綦讫蕲屺忾颀亓碛柒汔趿綮萁嘁蛴赍槭欹芑桤丌蜞謦祇锜玘扺|呇洓郪埼䓫跂徛婍棨愭墘碶踦磜鲯谿|䯥䔾㱦畁喰刾㰗䠞䐤㫅軙㔑袳㞿忯䟷竐㩾㝄䇍矵舙䛛㩻䣀豈㘍㠍㠎騎焏萕鐖稘朞㰟㠱鬾㹄㙨䩯斊䶓㖢薺䗁竒緝㦢㓗㼮䥢罊蘄䔇䰇䀈甈猉霋䌌㜎䄎頎騏蠐踑訖唘礘䀙倛鼜蜝䐡夡䄢䬣㼤紪䄫欫唭鰭簱䰴帺鬿䙄湆湇䁈䱈䁉齊䡋魌籏噐㥓䩓䡔啔摖剘呚嵜䉝啟䅤㩩䭫䭬呮䅲䑴晵䭶鵸䉻䭼慼桼㩽慽捿䢀鶀炁玂璂纃㒅憇鶈䚉䚍㮑掑蚑䶒㞓岓邔碕䒗㞚䞚蚚亝䶞芞麡䎢暣禥綥㾨綨䲬檱疷粸綺䒻榿櫀盀緀䟄棄䏅䓅迉䏌臍㟓㫓䫔忔翗䧘闙㟚䟚僛濝㓞䏠㟢䳢竢㯦磧磩㣬諬釮䋯棲䛴䧵䏿裿諿缼趞螇漬傶䅩蚔扢愒肵斉蛣犵躩鸂鬐栔気錡氣錤攲娸鄿啓顣敧艩衹碁悊咠鮨悽旂藄諆棊磎淒鯕鏚軝懠盵蟿渓扱疧滊") ("qia" "卡恰洽掐|髂袷咭葜拤||㵄㮫抲䈓㦴鞐㰤䶗硈䁍䂒鮚㓤㓞㤉䠍䨐䜑愘圶㡊酠殎䶝䯊跒㓣䛩冾磍㧎帢鉥") ("qian" "前千钱签潜迁欠纤牵浅遣谦乾铅歉黔谴嵌倩钳茜虔堑|钎骞阡掮羟钤扦芊犍荨仟芡悭缱佥愆锓褰凵肷撖岍搴箝慊椠鹐圲|杄汧靬葴蒨墘磏孅|㝿䢪䑶橬䅾㹂濽㥞䤘馯㦿乹齦摼䐶鋟䋮䔔仱唊騝偂䅐䵖䵛䭠麉玪鶼䯡㓺淺鳽艌厱䭑䙺䆂熑䃛䇜㪁㡊刋攐鈐攑攓儙謙騚㨜鬜鬝㜞錢䈤欦漧㸫騫鰬圱鐱蔳䈴縴㐸蜸谸簽䨿䥅顅䍉灊籖鉗汘兛潛鉛婜譣䭤籤㡨顩歬䕭㩮䁮鵮孯嵰扲慳譴奷遷塹牽繾撁膁䪈䖍岒悓皘蚙箞㪠羥榩㦮䦲䊴檶㧄韆棈僉壍姏槏櫏篏諐黚㯠䫡軡臤槧瓩拪濳忴鳹㟻鑓㥶竏煔錎羬藖雃㢛撍朁灒歁鰜鑯幵麕輤鬵蕁葥粁蚈媊傔掔綪銭燂拑嗛篟揵釺廞俔脥燖鈆鉆") ("qiang" "强抢墙枪腔锵呛羌|蔷爿襁羟跄箐樯戕嫱戗炝镪锖蜣丬|玱矼鸧蔃|戧搶剏將強繦摪勥羥錆猐漒謒嬙蘠唴䵁牆蹌鑓㩖䅚艢嶈墏薔羗檣羫溬傸墻羻嗆槍鏘磢㛨篬鏹㱿啌刱彊椌牄繈蹡瑲熗鎗斨廧") ("qiao" "桥乔侨巧悄敲俏壳雀瞧翘窍峭锹撬荞|跷樵憔鞘橇峤诮谯愀敫鞒硗劁缲睄|硚燋|㱶䏆䦒䵲銚䂪䯨礉丂殼潐譑㩰嶠䚩喬勪鞽㺒䫞㨽鐈䀉㤍頝鄡㴥鄥帩鐰嘺䱁癄橋䩌蕎㡑繑陗譙顦幧嵪鍫鍬㝯繰鵲蹺㚁躈㢗䎗誚㪣嶣墧庨趬骹䆻㚽墽撽䲾燆䇌僑鏒韒槗髚髜䃝釥藮嫶翹僺郻磽毃犞幓踃踍顤菬摮磝喿殻蹻蟜礄簥塙敿墝趫竅偢荍橾箾") ("qie" "切且窃茄锲怯伽惬|妾趄挈郄箧慊唼癿||魥㙻䞣鰈㰤䶗鐑洯䌌㼤䫔䠍䬊愜笡踥匧㰰㤲㰼䤿穕籡㹤鍥㥦聺㾀悏㚗㾜䦧淁竊篋㛍藒㛙䟙鯜蛪㗫㓶㫸䈉帹稧㛗輵椄緁跙朅") ("qin" "亲勤侵秦钦琴禽芹沁寝擒覃|噙矜嗪揿溱芩衾廑锓吣檎螓骎|嵚慬|橬䅾梫埁䃡鈂䢈藽㱽頜瘽䥆䶖嶜厪埐鋟菳㕋䵖䇒㓎蠄搇㤈瀙鈙䈜吢㘦儬䠴䔷耹欽坅顉㩒捦鵭㝲靲赺赾㪁媇抋䖌㮗㢙㾛誛肣䦦親㞬撳斳螼鮼澿嫀懄曋寑菦寴䥅顩扲蚙軡臤忴鳹㛙䰼㕂笉䫬昑唚琹綅庈嶔雂懃珡寢菣駸鬵鈊") ("qing" "情青清请亲轻庆倾顷卿晴氢擎氰|罄磬蜻箐鲭綮苘黥圊檠謦鸮|汫勍庼碃|埥渹䡖葝䵞㵾鶄㢣擏殌㔀親漀頃樈輕䔛夝䌠甠氫罊鑋靑靘剠啨慶䝼掅䞍暒䲔傾檾狅寈請鯖磘䋜䯧㷫郬㯳淸㩩䋯棾䂩凊莔殑殸廎軽") ("qiong" "穷琼穹|邛芎茕筇跫蛩銎|䓖嬛|㵌憌舼䧆䃔㤨蛬㑋輁㼇匔儝焪焭䠻䅃桏睘煢橩卭赹䊄宆蒆㒌熍㮪窮䆳㷀竆瓊藑䛪㧭藭棾䁚瓗㝁笻瞏璚惸琁") ("qiu" "求球秋丘邱仇酋裘龟囚|遒鳅虬蚯泅楸钆氽湫犰逑巯艽俅蝤赇鼽糗鞧|訄萩鹙璆|㛏蓲䠓醔釓牫亀龜㲹䔔䊆㺩觓鳩趜唒㧄㐀訅紌鰌鰍逎㼒䠗脙䤛搝渞丠㐤蠤䜪崷㤹朹鱃扏穐汓浗恘㭝㥢㕤煪湭虯蝵梂鮂䆋玌肍莍殏㞗媝龝趥鞦㺫䞭皳䊵䎿䣇㟈僋秌篍㷕賕蟗釚緧㧨䟬苬叴䟵蛷頄鰽偢坵絿鶖銶厹鯄盚觩毬巰橚櫹") ("qu" "区去取曲趋渠趣驱屈躯衢娶祛瞿戌岖|龋觑朐蛐癯蛆苣阒诎劬蕖蘧氍黢蠼凵璩鞫麴鸲磲彡|坥岨胠砠竘袪䓛焌麹鼩灈|㲒䪨䠓趨䓚㪯趍耝欪䢗蚼㽛㜘絇䅓䕮㩴蝺趜斪䢹䆽䗇䏣䌌㚁㤲㾀鼁㠊欋䠐鸜鴝刞䀠爠匤㰦戵紶匷蠷鰸㜹伹浀筁驅葋鱋詓䝣䁦齲䵶鑺镼魼䂂㖆嶇憈鶌璖㲘䶚躣䞤䒧粬麯覰誳岴閴螶覷厺覻抾軀㧁忂菃闃㣄駈䟊翑蟝臞㫢䋧㯫竬淭翵髷區詘怚佢跙阹佉豦籧敺呿麮懅駆胊軥脥") ("quan" "全权券泉圈拳劝犬铨痊诠荃|醛蜷颧绻犭筌鬈悛辁畎|佺琄婘棬瑔鳈|鐉酄鸛䌯㩲腃韏埢啳狋䅚鰁輇權䄐縓騡洤権䀬䠰搼硂虇孉䑏呟絟齤絭恮詮汱葲顴湶牶犈䊎銓綣㒰烇巏峑䟒觠㟨駩㟫勸姾槫謜矔圏踡弮蠸甽灥牷惓勧跧讬") ("que" "确却缺雀鹊阙|瘸榷炔阕悫攉汋|囷埆隺碏|䱜䍳寉㹱䲵䀇䐨㲉殼蚗䢧䟩鵲墧㹤崅㰌礐愨礭㴶琷缼㕁㩁㱋灍硞慤㱿蒛趞㾡䦬皵確毃闋䇎闕燩䧿棊塙搉卻碻") ("qun" "群裙|逡麇|囷|歏䆽麏䊎夋帬䭽㪊宭㿏裠峮輑麕箘踆羣") ("ran" "然染燃冉|苒髯蚺|䎃|䇋嫨㹱䔳䕼䶲㒄䰯蹨䳿㸐䤡㜣嘫繎䑙呥橪衻䖄冄㾆袇蚒袡䒣媣蚦㚩㲯肰珃䫇姌㯗髥㿵䣸㦓蛅") ("rang" "让壤攘嚷|瓤穰禳|儴蘘瀼|䑋爙鬤穣䉴獽㚂讓躟懹欀蠰譲壌勷纕忀") ("rao" "绕扰饶|娆桡荛蛲||犪橈蟯繚嬈饒襓蕘㹛繞㑱隢䫞擾穘遶") ("re" "热惹|喏|爇|㻰蹃渃熱㳧捼") ("ren" "人任认仁赁忍韧刃纫饪|妊荏稔壬仞轫亻衽恁葚纴鸮讱|菍|釰㤛䚾䛘㲽䄒䀔賃餁刄紉鈓紝栠栣䴦朲㠴鴹䀼㸾䌾䭃杒魜扨靭靱屻銋認梕芢㶵袵秂忈韌忎軔䋕䏕姙軠飪仭䇮䏰秹㣼訒鵀絍腍牣荵肕棯") ("reng" "仍扔|||䄧㭁䚮㺱辸礽陾芿") ("ri" "日||驲|釰氜鈤䒤囸衵馹") ("rong" "容荣融绒溶蓉熔戎榕茸冗嵘|肜狨蝾|瑢镕|軵坈䋴䄧爃㘇䤊搑蠑縙茙䠜瀜褣鴧鰫䘬䈶㼸穁䡆㝐㭜嵤䡥絨䩸宂䢇傇㺎螎㲓鎔㲝㲨榮榵媶嶸鎹䇀㣑鷛駥曧䇯髶烿䄾縟巆搈嬫傛嫆栄氄羢毧") ("rou" "肉柔揉|糅鞣蹂||莥䥆㮟䏔䋴䢇䰆鰇䐓渘騥䄾瑈鍒鍕蝚煣㽥腬媃粈宍沑鶔㖻瓇䧷輮葇楺禸韖厹鑐") ("ru" "入如乳儒辱汝茹褥孺濡|蠕嚅缛溽铷洳薷襦颥蓐|傉嬬臑|檽㱶吺䞕㨌㳶㼋㾒䤉䫱䘫䰭嗕䋴蒘䐓䄾㨎鴑縟帤渪䰰偄桇㹘顬鱬肗邚侞銣媷㦺䋈曘燸挐獳鄏鴽筎蕠醹袽擩蝡鑐繻") ("ruan" "软阮|朊|堧媆瓀|䆓㮕檽㧫䙃䪀㓴㜛䙇䎡㨎偄燸礝輭㼱瑌腝㽭䞂碝䪭緛軟䓴耎蝡撋壖") ("rui" "瑞锐睿芮蕊|蕤蚋枘棁|汭|䞩㧫䂱䦌䄲䳠䇤䍴㻔䜭㕙鈉抐㨅㹘蘂蘃甤蜹䌼蕋䅑桵㮃㲊㪫銳壡惢㛱䓲㓹綏苼䬐㢻笍鏸撋婑繠橤緌叡鋭") ("run" "润闰|||㝄䏕䏰㠈橍閏䦞閠瞤膶撋潤犉") ("ruo" "若弱偌|箬|鄀婼蒻僇爇|㬉挼䚥渃鰙䐞焫鰯楉叒捼撋鶸篛") ("sa" "萨洒撒|飒卅仨挲趿脎靸|潵|䑥钑鞈䓲䬃䘮訯㽂䙣蕯㒎䊛隡㪪颯馺㳐櫒挱㚫泧䛽鈒攃灑薩鏾摋纚躠") ("sai" "赛塞|腮噻鳃||㘔鰓䈢愢簺顋恖毢嗮㗷賽毸䰄揌僿儛") ("san" "三散伞|氵叁糁馓霰毵彡|潵|傪謲叄悷鏒嘇䀐攕㤾䉈饊䊉閐㪔傘犙㪚糂䫅仐俕糝糣糤䫩㧲毿帴弎鬖繖佡鏾蔘") ("sang" "桑丧嗓|搡颡磉||䘮褬桒顙䡦鎟䫙喪纕") ("sao" "扫骚嫂缫|搔瘙臊埽缲鳋|溞|鰺㺑鯵鄵鐰繰鰠騷䐹䕅繅鱢掃䖣掻矂㿋㛮㲧髞㺐喿氉騒慅颾縿橾") ("se" "色塞瑟涩|啬穑铯槭|洓㴔溹璱|鉍䊂粣拺琗㽇㾊㺩㻎瀒䨛䔼㱇穡䉢繬歮歰㥶澀澁趇㒊犞㮦銫嗇飋擌懎濏翜㻭雭栜瘷鏼漬廧渋譅轖濇鎍闟") ("sen" "森|||傪㜗摻罧襂幓穼曑槮篸蔘椮") ("seng" "僧|||鬙") ("sha" "沙厦杀纱砂啥莎刹杉傻煞赊|鲨霎嗄痧裟挲铩唼歃||硰剎㵤䯫唦啑菨㠺䀉䬊㰼歰翜挱猀䈉儍紗㰱蔱帴帹倽䝊䵘桬乷粆䶎䮜榝喢鎩㚫閯殺廈鯊鯋㛼髿㬠閷賒濈萐樧摋魦箑翣") ("shai" "色筛晒|骰酾||攦釃簛䵘㬠㩄籭繺閷篩曬諰㴓簁") ("shan" "山单善陕闪衫擅汕扇杉掺珊禅删膳缮赡鄯栅煽姗跚鳝|嬗潸讪舢苫疝掸膻钐剡蟮芟埏髟彡骟|飏烻掞晱墡嶦鳣|㱯㨻㱚摻㺑䗞笧脠䡪㹽禪單㯆䛸灗潬撣㚲䩔閄蔪㬭㴸㾆嘇䀐襂幓贍訕笘椙㨛䄠鐥刪椫䴮騸挻䠾䥇䱇䱉饍鱓鱔繕陝杦譱赸剼敾陿䦂閃䆄䦅檆熌㪎銏㚒㶒傓邖澘覢㪨䚲羴鯅㣌姍僐軕㣣釤狦磰煔襳顃柵䁴䪌僤痁儃謆搧縿穇睒陜摲墠羶蟺猭樿鱣") ("shang" "上商尚伤赏汤裳|墒晌垧觞殇熵绱|埫|爙丄蔏䬕尙漡鬺扄鑜慯湯銄殤螪傷緔賞姠仩滳觴恦禓塲愓蠰謪踼鞝") ("shao" "少绍召烧稍邵哨韶捎勺梢|鞘芍苕劭艄筲杓蛸潲睄|玿柖|韒娋輎㸛䔠䬰圴紹牊佋蕱䙼㲈袑䒚㪢綤颵鮹竰䏴㷹䈾萷綃弰焼卲莦燒旓髾") ("she" "设社摄涉射折舍蛇舌奢慑辙赦赊佘麝|歙畲厍猞铊揲滠阇|奓畬|䤁㵃䬦挕䠟䕣㓭䰥涻䀹輋䜆䜓摵䏴䀅㴇欇騇㰒䄕攝設䤮䌰䠶䬷弽灄譇鉈葉䁋捑㭙䵥鍦捨䁯䞌厙䂠㒤㢵賒賖蛥懾㤴磼闍摂蠂渉舎蔎虵檨韘肬慴") ("shei" "谁|||誰") ("shen" "深参身神什审申甚沈伸慎渗肾绅莘呻|婶娠砷蜃抻哂椹葚吲糁渖诜谂矧胂瘆屾|侁珅甡棽跱鲹燊瞫|㱯鰺參叄叅蓡鯵堔䫖䯂㚞罙䚓罧嫀曋䧵㛙嘇糂糝幓穼曑槮㰂㶒鯅䄕谉瀋瘎眒眘昚弞䰠氠訠阠頣㔤㜤甧㰮瘮紳訷嬸愼㵊腎敒兓㵕扟鵢魫鉮㥲詵籶涁薓㾕邥䆦宷侺妽覾裑諗柛鋠矤審滲峷䰼㜪頥㕥䅸蜄祳寀搷淰棯蔘椮脤葠籸讅駪黮兟姺抌") ("sheng" "生声升胜盛乘圣剩牲绳笙|冼甥嵊晟渑眚省|昇陞|㹌䋲椉娍㼩晠㞼䇸澠琞阩㼳焺蕂䱆鉎聖偗譝䁞湦鱦繩聲陹鵿殅䚇䞉溗斘㾪墭䎴憴箵貹榺䪿珄狌竍竏竓竔竕竡曻苼渻㮐乗熯褱殸縄鼪呏剰㗂勝泩賸") ("shi" "是市时实事十使世施式势视识师史示石食始士失适试什室似诗饰殖释驶氏逝湿蚀狮誓拾尸匙仕柿矢峙侍噬嗜拭嘘屎恃|唑轼虱耆豉舐莳铈谥炻豕铊鲥饣螫酾筮埘弑礻蓍鲺贳湜奭鳀|邿鸤䴓䏡浉祏栻媞鼫襫|宲㫅䈕䜵䜻恀䑛㢁徥㶴䶵㳏飭忯姼䜴忕䄷䲽眡啇楴鈟痑䤭釃佀螄䂖䦙飠籭篩鉈鍦䂠竍眂䰄褆眎弒舓嬕丗餙謚餝鰣簭鼭昰鈰䤱笶㸷褷㔺崼㱁湁鉂䩃鉃䭄獅鉇遈卋衋屍詍鉐塒㵓噓蝕睗兘識兙齛㕜㹝呞瑡湤試乨呩詩㹬乭卶㹷襹䁺鉽遾亊蒒䊓蒔視冟䦠䶡溡䒨䖨宩碩榯貰鶳銴㮶㖷箷䦹㒾枾䛈釋㫑烒叓揓峕濕䟗駛勢實瓧翨鯴釶柹軾飾鳾惿醳沶魳檡䌤馶觢秲徧戠鍉咶適鰤師戺絁時蝨葹実澨溮溼釈寔諟諡跩鳲旹識狧剸狶埶遰") ("shou" "收手受首售授守熟寿瘦兽瘠狩|绶艏扌||濤嘼敊夀㥅㝊䭭獸膄㖟垨綬涭鏉䛵壽掱荍獣収痩") ("shu" "术书数属树输束述署熟殊蔬舒疏鼠淑叔暑枢墅俞曙抒竖蜀薯梳沐戍恕孰沭赎庶戌漱塾|嗽倏澍纾姝菽黍腧秫毹殳疋摅丨|祋陎悆鄃隃婌稌翛摴疐潏|㵂䇬㫹䠼䙱暏䢞氀捒㟬䩳䭭鸀焂攄尌㜐倐紓圕贖尗樜樞䘤䴰錰䠱輸䜹䉀䝂絉豎術䑕荗鵨襩䝪兪虪屬㽰䩱潻㾁蒁䎉鶐掓㒔㶖䞖䆝䢤薥侸璹庻凁㷂㳆俆濖軗䃞鏣竪糬㯮埱藲㛸書㣽跾㻿鮛咰㡏㓱捈瑹怷蒣忬鷸蠾孎䟉鐲謶籔踈鼡儵樹潄癙襡鉥數杸橾綀钃疎裋韣藷刓朮") ("shua" "刷耍|唰||鮛誜") ("shuai" "率衰帅摔甩|蟀|缞|釃綏帥繂孈䢦咰卛縗") ("shuan" "栓拴涮|闩|腨|閂䧠槫") ("shuang" "双爽霜|孀泷|骦礵鹴|漺䔪䨥瀧傱欆樉縔鸘騻㼽灀孇慡䡯㦼雙䫪䗮滝驦艭塽鷞") ("shui" "说水税谁睡绥|氵|帨|㔑娷㥨㝽䳠䲧䬽閖誰稅挩氺脽捝䭨祱㽷瞓涗涚說裞蛻説") ("shun" "顺瞬舜|吮巛楯||䐏䞐䴄㯗順鬊䀢䀵橓䑞㥧賰蕣瞚揗眴") ("shuo" "说数硕烁朔|铄妁槊嗍蒴搠汋||䁻洬銏㸛䔠碩㮶帥說䌃爍䀥欶䈾鑠獡鎙矟揱哾萷數説箾") ("si" "司四思斯食私死似丝饲寺肆撕泗伺嗣祀厮驷嘶|锶俟饴巳蛳咝耜笥饣纟糸鸶缌澌姒汜厶兕菥|佁虒涘偲楒飔凘|厠廁枱賜傂䃽㜦竢愢恖鐁瀃㐌洍謕簛蜤騦娰鼶㸻鈻佀㹑㭒噝孠杫蕬牭鉰絲鍶蕼㕽肂螄貄㾅䂖亖禗䦙䎣媤禩㚶榹泀䇃磃㣈燍蟖鋖駟飠䏤泤飤鷥緦俬釲蟴糹飼籭䒨㮐逘鈶螔飴銉価儩罳覗禠颸廝柶餧") ("song" "送松宋讼颂耸诵嵩淞|锶怂悚崧凇忪竦菘㧐|娀|㬝樬棇蘴鎹鬆頌蜙訟㨦䜬倯愯餸捒楤䉥慫㕬㩳聳嵷硹枀䢠梥誦檧枩傱㮸庺憽濍柗䛦駷摗鍶吅憁揔漎") ("sou" "艘搜漱|擞嗽嗖叟馊薮飕嗾溲锼螋瞍|蒐廋|䈭䐹捒騪瘶䈹餿摉摗䉤㵻傁醙䮟㖩鎪颼廀䏂蓃㛐叜櫢藪㟬擻䩳膄鏉欶棷颾鄋謏獀籔捜潚") ("su" "速素苏诉缩塑肃俗宿粟溯酥夙|愫簌稣僳谡涑蔌嗉觫窣|骕甦傃溹鹔蹜|梀䇤棴㥛圱㔄㴋䔎㴑蘓謖㬘㜚䌚栜㨞稡縤洬縮訴蜶䘻㴼䅇㑉㩋塐䥔㕖㑛㝛遡潥遬䩳䑿肅膆玊誎殐䎘趚璛憟㪩溸碿鯂㯈鋉嫊䏋藗㓘珟䃤櫯䛾埣樎摵僁莤䘘㲞遫蘇樕餗愬穌驌鱐橚潚粛榡囌泝鷫") ("suan" "算酸蒜|狻||䔉㱹笇㔯匴祘筭痠") ("sui" "随岁虽碎尿隧遂髓穗绥隋邃|睢祟濉燧谇眭攵荽|葰嶲璲穟襚旞|㥞嗺䲀陏韢靃䤭䜆䅑䆳鐆夊䜔䠔嬘㴚娞䔹繀遀䍁䭉䉌䅗嵗䥙譢㵦湪煫歲䡵荾檅綏芕鞖亗熣䢫禭誶㒸㞸膸澻瓍滖雖䯝㻟埣賥㻪哸毸㻽倠䯿粋繐鏸撋砕瀡鐩穂睟歳繸浽檖隨巂髄雟縗") ("sun" "损孙笋荪|榫隼狲飧||喰䐣摌㰂損愻㔼㡄筍䁚蕵㦏薞鎨箰蓀槂飱㨚鶽搎簨猻潠孫扻") ("suo" "所索缩锁莎梭琐|嗦唆唢娑蓑羧挲桫嗍睃|葰溹蹜|縒鎈嫅䌇靃惢㮦縮蜶樎琑簔䈗䐝逤褨挱瘷䵀摍䅴摵䞆莏溑趖鎖䖛暛䂹鎻鮻㪽䞽鏁䣔䗢嗩鏼髿䲃㛗簑瑣璅鎍傞魦麞") ("ta" "他它她拓塔踏塌榻沓漯獭|嗒挞蹋趿遢铊鳎溻闼靸跶褟|溚阘鞳|䑽呾墖鎝㯚䳴䪚䠅鞈鉈䌈崉䈋䜚鰨䈳䍇鑉䑜䍝䵬譶蹹㹺獺㭼橽䶀䶁躂羍㒓䎓龖榙鮙㺚鞜傝躢亣嚺撻誻涾澾䂿濌㯓迖㣛㳠䓠㛥闥㳫㗳㣵㿹㧺鎑咜闒錔搨祂遝牠嚃鎉龘禢狧毾闟") ("tai" "台太态泰抬胎汰钛苔薹|肽跆邰鲐呔酞骀炱||枱㙜箈忕奤㸀㬃㘆䈚舦鈦嬯夳籉態䑓孡㥭坮㙵㑷粏鮐㒗溙冭檯䢰颱炲㣍㷘駘擡燤䣭菭秮忲旲臺囼䔶鈶詒珆斄儓") ("tan" "谈探坦摊弹炭坛滩贪叹谭潭碳毯瘫檀痰袒坍覃|忐昙郯澹钽荨锬镡赕|倓菼啴惔榃璮磹亹|鐔䀡嘽繵㺥㵃䢻䗊㛶舕䨢嘾㵅㽎潬㫜痑悷䑙僋㒎㪔㶒㜤傝嘆舑䜖錟攤騨䐺䕊罎㽑婒灘譚橝湠䉡鉭癱醈䦔貚憛㲜䞡䊤抩貪㲭墰䆱憳墵憻緂壇曇談㷋䏙壜鷤裧賧䃪藫埮擹顃譠餔弾彈禫燂儃贉餤怹罈歎驔襢醓醰黮嗿") ("tang" "堂唐糖汤塘躺趟倘棠烫淌膛搪|镗傥螳溏帑羰饧樘醣惝螗耥铴瑭嘡蹚|鄌䣘镋|䠀䕋㦂閶欓逿嵣闣䞶㼒漡湯戃䌅鐋㜍伖鼞漟爣餳餹㼺儻饄䉎偒橖坣摥蝪䅯赯㙶啺㭻㑽钂膅㒉傏劏鎕薚隚禟㲥鎲榶鶶鞺糃磄蓎䟖篖矘燙糛闛䧜鏜㿩曭愓簜踼煻") ("tao" "套讨陶涛逃桃萄淘掏滔韬叨|焘洮啕绦饕鼗丶|弢梼绹慆|夲䄻濤䛬幍燾轁䛌䱇㲈涭騊討䬞謟縧蜪錭饀㹗䵚絛詜瑫祹醄鞉㚐䚯鞱䚵槄嫍韜翢駣裪迯飸鋾㣠夵䑬抭窾匋縚搯鞀檮綯咷") ("te" "特|忑忒铽慝|螣|貸鴏脦㥂貣蚮蟘鋱㧹犆") ("teng" "腾疼藤滕|誊熥|螣縢䲢|痋霯邆䮴僜謄漛鼟鰧䠮儯騰幐籘驣䕨䒅䲍膯駦籐") ("ti" "体提题替梯踢惕剔蹄啼屉剃涕|锑倜悌逖嚏荑醍扌绨鹈缇裼俶鳀|钖虒䏲遆媞媂瑅髢禔䗖䴘擿趯|䬫䣟䫮䈕徥徲姼焍奃詆䱱楴䶍䞶諦惖啑䣠嵜謕磃褆㖷䢰鷤鬀鬄褅䨑鐟䌡錫挮㬱䔶崹鴺漽䬾題偍蹏歒㡗䙗鍗蕛屜鵜屟䅠罤蝭䝰䪆䶏䶑㖒嚔厗鶙䚣掦趧䎮碮躰禵骵鮷銻嗁䧅軆鷈鷉迏苐體䯜䣡㣢㗣俤㯩髰䛱鯷緹䣽惿䩟㥴鮧瓋䄺渧珶稊騠逷戻穉籊睼綈悐鶗薙殢揥洟桋") ("tian" "天田添填甜恬|腆佃舔钿阗忝殄畋锘掭湉|沺盷淟晪颋瑱黇|㧱娗奵錪鈿顚敟䧃䏦䣶㤁䬯䄹䩞跈鍩䑙沗䄕㜤㑷緂䵺㐁䠄䐌倎舚甛唺䄼䄽䩄㙉㥏畑䡒睓煔靔䥖婖䡘䑚靝酟塡兲㮇覥㖭璳㶺悿㧂鷆胋磌觍闐賟䟧䣯痶搷琠靦鼪睼餂屇窴菾銛鷏") ("tiao" "条调挑跳迢眺|苕窕笤佻啁踔粜髫铫祧龆蜩鲦|㕮朓嬥|趠朷䧂銚䂪調㩖脁萔㸠樤䠷鰷晀聎祒䱔齠䩦絩㑿芀䎄䒒條鮡庣鎥宨窱岹䖺䳂㟘鋚旫䟭䯾蓚蓨艞䑬鯈誂頫恌趒鞗覜斢岧糶") ("tie" "铁贴帖|锇餮怙萜揲||鋨聑惵䩞䑜䂿䴴鐵䥫䵿貼蛈飻鴩惓怗鐡鉄驖僣銕蓺詀鉆呫") ("ting" "听庭停厅廷挺亭艇婷汀铤烃霆|町蜓葶梃莛圢|侹珽烶珵桯颋渟䗴|庍䫖䁎侱䇸䅍㼗娗甼忊鋌濎烴鯅耓鼮嵉䱓聤㹶䵺聼艼聽涏䦐邒鞓誔厛閮榳諪廰廳䋼脡頲朾蝏楟筳聴庁綎") ("tong" "同通统童痛洞铜桶桐筒彤侗甬佟潼捅酮|砼瞳恸峒仝恫硐嗵僮垌艟茼湲熥|峂哃烔㛚鲖橦曈穜皦|炵峝蚒䴀氃㠉樋㤏㸗爞㼧鼨眮蘳㠽㼿晍鉖慟絧統浵鉵詷綂憅銅䂈㪌㮔䆚庝犝粡膧䶱䮵䆹䳋燑㣚姛㣠狪勭秱迵蜼赨硧偅鉥餇朣衕獞筩蕫罿鮦痌蓪囲湩") ("tou" "投头透偷|钭骰亠||諳㼥敨䕱鋀䡩㤟㰯㕻㳆埱䚵鈄紏蘣頭坄䵉㡏䱏酘鍮偸婾㢏㪗㖣䞬䟝㓱綉諭飳牏媮妵黈斢緰皁") ("tu" "土突图途徒涂吐屠兔秃凸荼|钍菟堍酴|梌葖稌腯㻬|啚鋀摕嶀趃腞䩣宊迌䴛䭭圕㒔䤅䠈唋圖圗堗圡怢鈯鼵捈兎鍎鵚筡湥潳䅷㭸捸瑹涋䖘馟鶟蒤庩莵凃䣄鷋㻌䳜廜痜䣝㻠揬㻯鋵鷵釷駼跿䔑墿鵌悇檡斁瘏塗嵞鵵禿図峹") ("tuan" "团湍|鹑疃抟彖|猯煓|墥褍剬䳪湪褖團䜝㩛䵯摶貒䊜檲鏄黗槫糰鷻鷒嫥篿漙慱剸団畽鱄塼") ("tui" "推退腿褪颓蜕|忒煺|焞魋|㥆䩣墤謉騩饋㰐脮蛻怢䀃蘈弚娧尵頹頺頽蹆橔㱣䅪蹪䍾螁㞂㢈㦌㢑㾯㾼㾽骽俀㿉䫋僓㿗㷟藬侻㟎聉㳷讉㢂穨隤蓷駾啍") ("tun" "吞屯囤褪豚|臀饨暾氽挦鲀坉|忳焞|錪憞蜳㬿㧷䀫膯黗螁㼊霕朜噋呑㩔豘㹠㖔㞘臋飩拵庉啍魨畽涒芚軘旽讬") ("tuo" "托脱拓拖妥魄驼陀沱鸵驮唾|椭坨佗砣跎庹柁橐乇铊沲酡鼍箨柝棁|侂萚|䲦仛㵃槖鬌䅜袉莌憜馱軃㯐踻㰐鋖綏鉈挩捝騨鼉鴕鰖託㼠砤鼧㸰㸱䴱堶䰿鵎䡐汑杔楕籜驝魠橢扥饦䍫彵䭾㾃咃䲊䪑碢袥岮馲涶侻㟎狏䓕拕駝駞毤迱嫷矺毻㨊袘扡駄蟺説蘀阤脫紽陁詑驒鮀媠讬沰撱跅飥") ("wa" "瓦挖娃洼袜蛙哇|佤娲鲑腽|畖窊|屲嗗窐䖯䍪帓㒝鼃㼘䠚漥攨㰪搲聉啘膃徍咓媧窪䎳䚴邷劸韈㧚嗢韤黳䯉唲鮭襪穵溛") ("wai" "外歪|崴呙||䴜瀤竵㨤䶐䠿㖞顡喎") ("wan" "万完晚湾玩碗顽挽弯蔓丸莞皖宛婉腕蜿惋烷娩|琬畹豌剜纨绾鲩脘菀芄鞔箢塆|妧涴婠椀|㺜㼝㝃㽹䏦輐捖錽鎫鋄䯛䈮䑱萬莬䨲薍孯䵥贃倇紈唍贎頑琓脕萖㸘踠帵㜶䘼鑁葂䩊䅋睌彎卐䥑睕㽜灣潫㝴䝹晼綄岏抏梚䖤貦綩綰䂺䳃蟃䯈盌鋔䗕埦忨仴䛷㿸䛃莧㹉魭蚖鋺鄤澣澫夘絻掔刓輓卍汍鍐捥晩翫夗惌") ("wang" "王望往网忘亡旺汪枉妄|惘罔辋魍尢|尪忳|朚臦㔞㑌忹盳䒽琞徍瀇㴏䤑輞䰣尣尩尫蝄罒兦彺暀徃蚟莣網誷亾㲿㓁䛃䋄䋞棢蛧迬菵㳹仼抂朢迋") ("wei" "为位委未维卫围违威伟危味微遗唯谓伪慰尾魏韦胃畏帷喂巍萎蔚纬潍尉渭惟薇苇炜圩娓诿玮|崴桅偎逶猥囗葳隗痿猬涠嵬韪煨艉帏闱洧沩隈鲔軎霨㧑|沇峗洈硙硊琟廆煟溦碨薳鳂螱皦鳚亹|㥨濻䙟䍴㺔㧡㙔䩈䅏饖詴䇻癐䲘䗆䤥㸵潙䍷溈䣀㧪㙗㟴䠑㨒䦱䫥䥆䵢䊊䓺㻰䩞䱞㮃㛱䛪膸㾯䫋鰖䲊䓕贀謂鰃愄鰄䜅愇欈㨊䬐䬑嬒踓㠕錗㬙䘙䜜瀢崣䈧儰椲蜲餵蘶䔺霺蜼䬿蔿幃偉䑊轊䵋瑋㭏䝐㕒煒癓婔嵔違浘蝛衛㥜䉠鍡葦葨䥩㱬荱楲腲䭳䵳䡺遺偽䙿潿醀䲁媁厃㞇隇鮇䪋蒍璏讏㖐㞑䞔斖䪘媙犚芛躛喡㦣覣媦犩骩骪鮪徫熭維喴梶䮹覹颹為㢻懀矀闈㷉諉揋菋韋鏏韑韙叞䧦㟪䃬緭緯藯濰燰㣲蓶䗽苿唩瓗猚茟趡濊恑瞶峞捼穌鼪囲撱圍頠蘤餧渨鄬爲椳褽湋鍏衞蝟罻讆薉暐躗鮠骫徻溾磈痏磑烓壝僞韡寪") ("wen" "文问闻稳温蕴纹吻蚊雯紊瘟汶|刎璺玟阌芠|炆缊榅辒煴蕰鳁馧|㼂䦟䦤䦷䐇㵮顐呅㡈㨉忟㟩莬呚脕渂䘇紋鴍瘒鴖脗䰚鰛琝鼤鰮昷輼問彣瑥㝧穩塭魰豱桽瞃蚉妏熓㒚殟螡㖧溫肳䎹馼䎽閿蟁㗃闅駇闦珳㳷緼鳼揾褞藴歾閺絻搵轀穏聞呡抆皁") ("weng" "翁嗡|瓮蓊蕹滃|鹟|䨴㙂霐㘢䐥䤰㜲嵡奣聬浻瞈鎓暡勜㹙甕齆罋塕螉鶲") ("wo" "我握窝沃卧挝涡斡渥幄|蜗喔倭莴龌肟嗌硪踒|偓涴馧|㠗䮸艧蒦瓁矆臒龏蝸渦濄䙠䁷䇶䀑腛媉踠䩊䂺仴瞃䰀䠎㠛焥唩嬳萵楃䁊㱧齷捾窩㦱涹撾濣臥㧴枂雘擭薶捼婑猧婐捰") ("wu" "务物无五武午吴舞伍污乌误亡恶屋晤悟吾雾芜梧勿巫侮坞毋诬呜钨邬捂鹜兀婺|妩於戊鹉垭仡浯蜈唔骛仵焐芴鋈庑鼯牾怃圬忤痦迕杌寤阢靰铻屼|旿郚胠洿峿珸珷鹀煟|㤇㘬蘁堊䓊埡䨁陚釫鼿㱱扝趶䚈䁷堥㝟䀛霿雺無䉑蟱㒇墲䅶䜑渞㐅伆鄔洖騖弙霚逜鰞茣霧娪娬鴮㐳㬳吳倵摀齀䑁㑄乄敄嵍歍鵐陓㡔譕腛鵡䍢塢奦瑦䡧嵨蕪剭㵲㹳㽾莁熃粅誈䒉媉岉躌䦍䮏窏螐璑禑隖䦜玝悞鎢誣誤溩憮瞴䎸箼鯃䳇俉㻍䫓䃖務嗚廡鷡忢䛩蓩䳱嫵矹㷻䟼兦亾熓䵦扜齬盓悪惡膴鶩兀甒儛噁橆杇呉啎潕汙汚扤祦遻卼麌碔沕悮窹烏軏鋘鋙杅皁") ("xi" "系西席息希习吸喜细析戏洗悉锡溪惜稀袭夕晰昔牺腊烯熙媳栖膝隙犀蹊硒兮熄曦禧茜嬉玺奚汐徙羲铣淅嘻|歙熹矽蟋畦褶郗唏皙隰樨浠蜥檄郄翕阋鳃舾屣葸匚螅咭酾粞觋欷僖醯鼷裼穸饩舄禊菥蓰郤恓晞豨潟窸䜣|屃钖肸咥俙饻枲绤棤睎傒㴔嶍嶲憙暿熻谿釐鳛巇酅爔|觿娭䑂誒䚫糦遟㒆㓾欪䵱䚂㦦戲㰥㱱㗲摡㳀嵆繫䒁墍旣䴛鼳瓕鈢鉩臈臘蝷嚊㜎䬣捿䚉䫔棲䦧䧿䘮㪪鰓䈢䨛㱇趇雭蜤杫燍䁯餙謚衋錫䯜䜁焁礂舃㠄嬆漇焈琋㸍㔒䀘縘漝椞焟稧鬩䈪怬焬欯戱騱䨳㤴謵怷㤸匸椺䐼霼餼唽騽橀豀齂恄葈噏屓煕屖歖㩗鵗鱚嵠㥡㭡䩤卥獥繥赥驨赩㹫蕮㽯豯襲晳㑶扸桸敼䙽㙾㵿䂀厀覀熂薂莃䢄徆螇熈䮎鎎媐銑㞒犔悕貕憘趘澙㚛螝隟䊠蒠覡覤瞦犧躧䲪嚱鎴蒵隵䚷肹喺熺㦻榽璽僁惁飁係蓆㿇䓇黊郋䧍壐矖翖黖瓗忚㣟䫣䛥忥㳧㗩鏭䏮諰磶觹觽㨙慀㩉奊䙎㩦㾙䚿䐅㘊餏䐖㰻羛緆戯扢蔇鈒繋莔鉨呬鸂磎巂雟瞚簁褉鄎謑渓瘜氥霫細縰蠵怸鰼譆卌潝蹝虩屭扱鑴綌纚犠疧徯滊囍習凞闟槢蟢燨釳狶釸盻諠") ("xia" "下夏峡厦辖霞虾狭吓侠暇遐瞎匣瑕|唬浃呷黠硖罅狎柙岈|叚翈鹡|䞩㵤䯟䒠蝦㙈㔠㭱嚇螛䒩㮫㿣敮閜挾浹徦埉䠍䨐䶝㰰㥦㛍廈陝陿捾縀丅夓鰕縖笚㘡䘥欱搳㰺谺轄鍜㽠㙤硤筪赮睱煵魻傄鎋䖎芐閕䖖䦖䪗疜炠疨颬鶷冾䛅㗇磍䫗懗烚俠珨鏬狹㗿諕仮舺憍陜謑舝騢祫蕸碬峽煆") ("xian" "现先县见线限显险献鲜洗宪纤陷闲贤仙衔掀咸嫌羡弦腺痫娴舷馅酰铣癣|冼涎暹籼锨苋蚬跹岘藓燹钐鹇氙锬莶霰跣痃猃彡祆筅挦伣|伭忺狝玹盷崄硍葴缐禒㬎孅|䦘䍎䐄譀㽉闞㦥㸝塪㰹礆㔓鰔䄯稴䵖䵛䵤筧見梘䶠覸糮䙹㔾䇒顈䡅㜷㲽壏懢蘚㱹䭑㦑薟㾾㯗欦譣㩮膁槏㯠臤㥦㛍攕姍釤揱錟饀銑㘅䘆蜆攇甉娊㘋唌錎䀏嬐贒嘕㬗瀗䨘搟尠餡䜢縣礥娨㜪訮輱㔵䨷鼸娹䤼褼鍁䁂䵇癇㩈㡉橌鍌䕔衘㭠啣䱤絤灦䝨㵪䥪獫癬蹮䉯顯婱䉳屳襳齴㭹鹹獻赻鱻㡾奾涀䞁㪇㺌㶍纎撏㦓澖纖䲗䚚躚銜咞䶟䶢誢䦥馦莧羨險羬㮭枮鮮瞯粯憲箲麲垷䒸㢺䢾㯀㳄㿅燅㧋䧋烍軐蓒臔藖珗胘蛝䧟賢㧥铦鋧毨㫫㳭姭䧮苮哯廯韯䃱僲僴峴櫶䃸䏹嫺嫻鷼臽㛾䗾搚䩙妶誸軒㰊麙䢭醶咁醎閒溓綅佡鏾縿県尟絃繊睍癎豏顕晛轞陥獮幰杴険玁撊閑銛憪綫嶮憸蚿韅秈僊俔仚線僩韱鷳諴鷴姺現鶱綖") ("xiang" "向项相想乡象响香降像享箱祥湘详橡巷翔襄厢镶飨|饷缃骧芗庠鲞舡葙蟓|珦瓖|䄈䛠䴂䦳䣈瓨缿銗塂䇨楿䤔夅䙹䒂鴹亯䬕銄姠欀項鄉餉鄊鐌鄕䔗栙䐟萫㐮䜶啌鱌襐晑潒饗鱜驤恦佭鑲詳絴鱶蚃薌羏䊑嶑麘鮝䖮䢽闀廂闂㟄緗鯗㟟勨跭㗽響皀澒閧鴂衖愬啍膷蠁饟纕嚮忀曏郷") ("xiao" "小效销消校晓笑肖削孝萧潇硝宵啸嚣霄淆哮筱逍|箫骁枭哓绡蛸崤枵魈鸮睄|洨恔虓涍猇翛敩滧熇皛薢蟏|囂㩭㒆㕺侾䒁絞䠛䴛鴵斆蟂訤髐㺒㪣庨骹燆騷䐹叜䇃㩋颵䌃揱䳋歒䎄䳂㵿薂踃㔅笅焇㤊嘋踍簘瀟嘨簫嘯㬵嘵萷彇虈啋婋驍歗穘硣顤䕧灱㹲灲䥵㑾筿綃斅䒕窙傚䒝梟誟憢皢㚣䊥撨鞩膮宯咲誵嚻熽藃曉毊㗛痟郩蟰俲謞澩獟䉰㮁嗃謼鵁筊勷謏橚潚縿莦箾嘐鴞蠨歊獢詨蕭呺暁銷効髇烋痚篠櫹殽鷕") ("xie" "些解协写血叶谢械鞋胁斜携懈契卸谐泄蟹邪歇泻屑挟燮榭蝎撷偕|歙亵楔颉缬邂鲑瀣勰榍薤绁渫廨獬骱躞揳澥|偰絜觟薢檞|㗨烲䞕䪥諜炧䍖䇋駭㜦㽳㷎䓳譮儶噧讗獦鬹㨒挾頡吤繲觧緳擷䬅㚗魼碿榝䁋䁯㢵齛孈屜屟䀘齂屓㩗䩤䙽㞒僁䏮䦖脅㸉瀉脋蠍㔎娎焎䔑㰔爕㨙搚攜㨝謝㰡㴬㴮紲伳愶缷褻㴽慀祄䕈㩉㽊䙊奊恊㝍䙎䭎瑎䉏㕐協齘㙝䙝㥟䡡蝢䉣齥㩦䵦䩧㭨卨㩪絬塮㙰䥱䕵衸籺衺䥾熁纈綊妎膎䦏㖑䦑䲒㞕䊝㒠䢡徢鞢垥冩㦪暬䚳鞵䚸斺禼㖿嗋糏翓㓔擕藛緤㳦諧旪寫㣯㣰韰燲拹㳿蝑䋶梋㡜㐖偞峫猲鮭褉滊脇蠏脥洩絏屧襭灺媟躠龤劦嶰疶㶸駴鍱") ("xin" "新心信寻辛欣薪馨鑫芯锌忻莘昕衅|歆囟忄镡炘伈䜣||庍㖕㻸鐔愖㽎㜦䅽姰㛙䎣阠㔤䪿㹷橝尋䜗嬜訢伩脪訫㐰攳樳䰼卂㭄襑顖孞煡桪噷杺䒖妡邤㚯䚱馸鋅㛛惞䛨盺俽馫㭡䛥礥軐㩪枔㾙鬵鈊舋鄩焮兟膷釁廞埶") ("xing" "行性形型兴星刑幸姓醒邢杏腥猩|悻荥陉惺饧擤硎荇省|钘骍铏婞瑆煋|䋲㒷娙㴆㬐銒䮍㚔箵狌餳餹興洐㨘㼛䰢㐩㼬䤯嬹渻䁄硏坓陘鍟㝭睲鮏㮐䂔皨馫垶篂䣆烆緈郉滎曐㓑臖䳙濚㣜㓝鋞觪䛭觲濴䓷鯹胻鈃讬騂倖鉶侀莕涬蛵嫈") ("xiong" "雄兄熊胸凶匈汹|芎讻|诇夐|哅焸賯䠗䎿訩㐫洶兇赨詾忷胷䧺詗恟敻") ("xiu" "修秀休宿袖绣臭朽锈羞嗅|岫溴庥馐咻髹鸺貅琇滫|珛脩|飍殠臰㩰㽲嚊脙鱃苬䜬㵻玊樇褏鵂潃齅饈繍㱙繡鎀綇綉㾋螑璓銝銹峀鏅烌蓚㗜俢髤鏥蓨臹鏽讬烋櫹褎茠糔") ("xu" "需许续须序徐蓄畜虚吁绪叙旭恤墟栩絮圩婿戌胥嘘浒煦旮酗|诩朐盱蓿溆洫顼勖馘肷糈砉醑媭魆|旴昫㳚珝垿冔谞欻湑嬬|蓲䨆嘼滀䧁暊㽳許歘滸烼掝蚼㒷䬎㖪䂸晇眗揟諿噓䎉俆㡏㦌朂伃㜅須頊䘏䔓䬔鬚倠䜡㤢鄦㘧㐨欰稰㰲怴伵漵稸㜿幁譃楈驉潊敍蝑䙒㑔魖虗敘㕛䱛虛聟㥠䅡詡魣偦蕦㑯㵰䍱籲卹汿沀瞁㖅䂆㞊銊續䢕䦗㚜疞窢蒣㾥㞰瞲㺷㦽䦽烅賉槒緒䛙盢㷦盨珬䣱䳳䣴㗵䋶壻妶蛡䬄謣惐鉥嬃縃訏欨訹慉鑐歔鱮呴繻殈侐続喣芧姁藇緖勗藚諝獝淢緰") ("xuan" "县选宣券旋悬轩喧玄绚渲璇炫萱癣漩眩|暄煊铉埙巽馔楦泫谖痃碹揎镟儇烜瑄鹮|伭玹咺昡晅琄衒愃暅暶禤嬛翾|㜗䛹䁔䥧喛㦥懁顈䡓姰㛐㔯㒸㻽㦏䚯䀏縣㔵癬㯀㿅㧋蓒䧟蜁吅䴉蠉䴋愋昍蘐贙㘣䠣䘩怰弲萲縼塇鉉繏蝖䍗䩙㹡䁢絢塤䝮䩰選䍻睻蕿䲂讂䮄檈梋㾌媗袨箮颴妶誸䲻鏇埍䧎矎軒鋗㳙嫙䗠㧦翧㳬懸藼諼㝁駨饌鐶狟煖佡敻琁蔙眴譞楥鍹鞙鶱璿諠駽玆") ("xue" "学血雪削薛穴靴|谑噱鳕踅嚯泶茓|峃敩|䠼㻡瀥㕰㷤䛎㨹䩈㦜矆䀜勪㔃䀗㔢疦䖼䋉謔㔧蒆㰒䆝㙾䒸斅䦑䜡怴瞲䬂䤕吙謞䨮鸴鱈䱑桖㡜䭥乴坹䎀㶅斈趐袕岤膤辥澩㖸㞽鞾㧒燢雤泬㿱䫻䫼䆷泧吷蹻疶學嶨壆觷鷽狘") ("xun" "讯训迅寻询循旬巡汛勋逊熏徇浚殉驯鲟荤薰|荀浔洵峋埙巽郇醺恂荨窨蕈曛獯挦珣|栒噀|㟧䃀㵌葷姰䡅㯠愻㡄咰尋攳樳卂桪㚯䀏撏潃䘩塤㜄㰊訊爋蘍蔒訓訙㨚伨㰬䭀㝁鑂坃畃䙉杊鱏鵔鵕鱘遜奞詢㽦顨潯偱䞊枔璕侚㢲䖲馴殾矄槆賐韗䛜毥壦駨勲勳廵䋸巺燻䵫稄鶽濬蕁灥潠揗鄩眴璿紃焄橁噚纁薫壎臐燖勛狥蟳迿篔") ("ya" "亚压雅牙押鸭呀轧涯崖芽哑讶鸦娅衙|丫蚜垭伢氩桠琊揠吖睚痖疋迓辂岈砑玡|姶堐猰|鶕椏圔唖啞埡䨙䆘䫖呾䍓軋䒁䀹拁㾏䂒㮞㴫㝦輅䖌㼤䫔㤉䧅疨㗇磍㹞䀴瘂漄笌稏猚鐚挜訝圠鴨氬䄰䰲㰳鼼䅉聐齖䵝㝞䝟蕥婭孲鵶齾厊庌庘劜䢝䊦䦪窫䪵犽雃䯉㧎壓铔俹㿿椻瑘釾厓輵烏潝鴉錏崕圧煆襾枒掗亜亞顔") ("yan" "研严验演言眼烟沿延盐炎燕岩宴艳颜殷彦掩淹阎衍铅雁咽厌焰堰砚唁焉晏檐蜒奄俨腌妍谚兖筵焱偃闫|嫣鄢湮赝胭琰滟靥阉魇酽郾恹崦芫阏剡鼹菸餍埏谳讠厣罨阽|觃沇䶮弇姶烻惔棪渰扊墕漹蝘戭虤黡嬿甗|䅬㜝洝䅖㱘婩晻䮗黬屵閼䪜㱌㒆懨䉷㺗墱䘶㺂鳱炏䶫䛳鬳㰽橪䌠鉛顩膁䦲䫡䦧挻挩捝錟䍾厃硏唌嬐㡉㵪齴䞁羬麲㥼黫訁琂䨄蔅嬊䀋䄋贋䴏騐猒萒焔㘖昖褗贗㘙愝䜩䌪㬫娫娮嬮騴鼴夵䤷渷簷礹椻儼椼䀽酀嵃遃顃楌䑍孍灎顏偐豓酓灔葕兗驗䭘魘䁙煙饜驠㕣偣彥敥剦䅧灧灩牪硯䱲乵艶艷㭺湺硽詽鹽䕾抁隁㢂醃㶄閆覎䲓㦔嶖䖗䊙麙㢛讞妟鶠麣䢥暥䎦㚧䂩䢭厭閰䂴厴嚴醶閹䊻閻躽檿㳂䓂㫃燄釅巌䣍㷔㿕懕曕巖巗巚珚䳛壛㫟䗡曣黤㓧壧櫩㛪鳫黭曮鷰姲㷳㗴篶姸䗺䳺裺諺㷼㿼䇾狿㖶阭囐淊溎齗穽豣撧齞縯鈆鴈鰋爓験鴳匽嵒嵓豔顔噞塩啱讌龑隒綖莚碞馣嚥喦喭厳醼傿鷃揅郔巘臙揜黶觾殗") ("yang" "样养央阳洋扬杨羊氧仰秧痒漾疡泱殃恙鸯徉|佯怏炀烊鞅蛘旸卬玚|飏咉钖垟羕|䍩㦹軮崸飬鴹氜勜歍䞁潒羏䭥楧攁鸉鐊養瘍眏鰑㬕䬗樣㔦阦鴦䬬輰氱崵霷䬺眻紻㨾慃䑆蝆詇䭐䁑佒瑒鉠煬敭䵮婸陽㺊䒋禓傟岟羪抰炴劷䖹㟅柍姎揚駚珜䇦懩㿮雵諹愓瀁昜楊鍚癢坱暘颺様胦") ("yao" "要么约药邀陶摇耀腰遥姚窑瑶咬尧钥谣肴夭侥吆疟妖|幺杳舀洮窈曜鹞爻徼繇崤徭荛轺铫鳐崾珧峣靿|垚窅猇隃猺媱|㑸鴁驁詏䳬䚆䯚䛂鑃銚䠛㬭䆗烄僥瘧纅㺒㓞嫍䒒㤊顤㑾䭥㹓鼼䔄倄約餆䌊搖䬙䌛訞䴠謠蘨鰩㴭尭堯㨱㔽䍃筄䙅楆䁏㝔䁘遙艞獟偠瑤齩䑬䉰鑰㵸婹穾㞁㮁岆宎熎袎讑㢓溔枖䆙䂚暚榚䆞覞䢣榣嶤䶧抭趭窯窰䖴䚺䚻䋂嗂鷂闄矅㫏㫐㿑烑蓔狕㿢䋤藥苭㟱仸軺柼怮㫍箹鎐恌眑騕餚謡愮祅葯葽殀喓窔傜嶢薬颻殽鷕飖揺燿鴢邎") ("ye" "业也夜叶野液冶页爷耶邪咽椰烨掖拽曳晔|谒腋噎揶琊靥邺铘玡|倻焆堨楪馌|䅬䅖㽢䎨痷㡋糦㓈䴾㱌㷸殕嘩㜇㧉礏鄓㴸䡾䳖䖣䮜葉釶啘䔑䭎㭨㩪䢡㖿䁆䭇歋䱒抴䇩䋵䝟䊦窫謁頁鸈䈎吔㐖爗嘢㸣餣䤳鄴䤶鐷爺㱉㩎㙒捓瑘驜偞䥟䭟䥡㝣靨㙪業潱㥷䥺鵺鎁嚈㪑鎑䲜殜㖡皣嶪嶫亱瞱澲㖶墷瞸枼枽燁壄曄曅䓉曗擛鋣忦䧨擨擪峫曵僷㗼釾饎暍熀狥漜蠮饁煠鍱殗埜擫皁") ("yi" "一以已意议义益亿易医艺依移衣异伊仪宜遗疑毅谊亦艾疫役忆抑乙译翼蛇溢椅沂逸蚁夷邑怡绎彝裔姨熠贻矣屹颐倚诣胰奕翌弈轶驿壹曳猗|臆弋铱旖漪迤佚翊诒怿痍懿饴峄揖眙镒仡黟肄咿翳挹缢呓刈咦嶷羿钇殪荑薏蜴镱噫癔苡悒嗌瘗笫阝衤欹佾埸硪圯绁舣搋酏劓乂匜祎浥锜螠杙|佁枍㑊叕昳胣洢宧扅扆勚㴔椸裛廙潩嫕鹝踦鹢燚繄簃|㱯㢊凒賹㼢䛖䳬糦㛳㔭䈕栘耛䔟䑛㮛拸䇼䧝䂽㲲䳀襗㕈䐙㵧䤭㔕㠖㱞䇣䄩䡾䰯䕥㵫䭲孴譺㞾㣇䧇狋钀䑄䖌䔇䱈䉝㾨綺䏌忔裿㐌㹑㚶鉈謚鉇詍䁺箷釶䴰䃞坄鴺䧅苐䣡彵狏迱贀遺焈焬歖㹫敼媐䚷㔎紲䣱辥鏔儀㘁㴁䄁䬁夁洂鸃億嬄䐅伇㘈怈頉㘊䴊縊㜋餏嬑㜒㴒礒萓䐖笖㰘逘鈘䰙蘙吚㰝䘝瘞嬟帠鈠輢阣眤頤䬥頥稦栧䄬䔬䴬弬霬欭䬮㠯瘱眱焲訲㔴鈶瀷䘸㐹褹崺攺㰻䌻謻䄿伿鐿乁䭂浂㱅䁆幆䭇㽈獈虉顊歋䱌䕍䱒詒㹓穓㝖㩘䝘捙湙豙彛豛驛㑜彜㵝䝝歝䭞彞恞䩟㙠敡顡詣艤㑥㕥䉨㵩譩衪㡫㹭呭陭㙯䝯譯鉯異議㱲晲浳㥴繶齸呹晹繹㡼靾䭿兿䖁㖂䢃鶃䞅芅暆䎈炈㦉膉讉䖊䮊肊撎榏宐䲑㞔殔肔螔瞖悘袘羛讛掜冝㢞㶠羠庡袣㚤㦤悥檥銥鞥㚦嶧鮧義熪醫嶬劮骮溰鎰醳䦴抴玴憶沶妷醷檹殹澺㲼垼熼誼貽㦾㺿䆿墿隿㣂䓃苅䯆珆緆迆秇跇䓈囈毉㫊俋懌曎㳑䗑旑釔㛕鷖䋚嫛藝䗟跠蛡苢鯣蛦䣧䧧鷧䇩竩痬棭寱燱寲黳釴飴䇵䋵瓵㓷䗷槷巸槸䓹觺㣻蟻軼郼䵝㸣㝣㙪㥷欥耴栺饎扡誃斁睪愒蜺鶂鷊衵錡鮨虵戺阤詑唈弌訑圛帟洟訳桋饐艗顗轙杝鹥齮偯豷襼瑿亄侇檍禕銕螘熤貤袲枻曀鷁柂駅泆峓黓藙蛜燡鳦勩壱埶蓺迻鷾喦皁樴") ("yin" "因引银印音饮阴隐姻殷淫尹荫吟瘾寅茵圻垠|鄞湮蚓氤鳏胤龈窨喑铟洇狺夤廴吲霪茚夂堙訚愔䜣|纼骃珢硍崟龂歅跱䲟溵禋慭蟫嚚|阥堷韽䗞䨙梀䡨㶣䒞㸧齦伒唫䖐玪䴛䴦䠴赺䌠㥲㒚㗃䰼㴽圁䤃朄㐆㴈㼉猌鈏㸒訔洕紖鈝蘟霠訡䌥蔩蔭崯栶䨸䤺㕂㱃䕃筃癊噖㝙乚湚䡛㹜㹞婣㡥㙬癮㥯陰酳荶陻㥼噾摿銀隂檃鞇侌璌粌蒑碒讔㖗憗㾙趛䖜䒡鮣㞤殥㪦斦銦㦩䪩檭馻檼垽嶾犾䚿苂䓄㧈烎凐鏔䇙囙懚滛鷣磤濥濦㣧黫绬飮諲飲秵緸櫽峾淾韾泿釿霒欭㝖酓䅧䕾㖶輑䏖㐺乑齗窾瘖縯慇絪婬靷垔憖冘隠隱螾誾裀闉廕駰傿") ("ying" "应营影英迎映硬盈赢颖婴鹰荧莹樱瑛蝇萦莺颍膺缨瀛楹|罂荥萤鹦滢蓥郢茔嘤璎嬴瘿媵撄潆|媖溁锳|䩕䒢㦹䚆㕲夃䀰焸㬐䔔㹵㚞唡嵤覮啨䵥鱦旲䋼䤰㜲滎濚濴绬㴄瀅蠅縈䨍攍鸎贏霒㨕攖鸚鐛䤝瀠蘡鴬褮瀯礯嬰蠳䀴瀴頴渶萾偀孆鍈䑉䭊塋罌譍鑍穎䁐䭗㹙㹚䁝籝㑞噟䕦楧浧蝧瑩㵬䙬摬癭譻孾蝿璄㶈㢍暎熒纓鞕颕㲟膡螢鎣碤鶧梬䪯鶯嚶藀盁巆應巊㯋僌緓瓔㿘濙營矨鷪廮珱䃷鷹櫻櫿䑍䭘眏䬬柍䇦耺䵴吋剉呎韹俓霙啢縄甇謍甖朠潁罃煐桜籯営嫈蛍賏応韺禜") ("yo" "哟|唷||嚛喲") ("yong" "用永拥勇涌泳庸俑踊佣咏雍甬镛臃|邕蛹恿慵壅痈鳙墉饔喁蕹颙|栐㶲埇㛚鄘鲬澭|㑙㦶揘飬鰫鷛䮵㣧㴄搈愑嬫㐯踴愹慂牅鱅塎癕㝘詠硧㽫彮噰癰嵱㙲悀傛醟銢㞲㦷䞻銿擁嫆勈㷏鯒苚嫞鏞柡䗤惥槦郺滽湧傭撧灉顒禜嗈雝廱") ("you" "有由又优游油友右邮尤忧幼犹诱悠幽佑釉柚铀鱿囿坳酉攸黝|莠猷蝣疣呦蚴莸莜铕宥繇卣牖鼬蝤尢蚰侑羑|祐朓浟鲉麀槱戭耰|㑸梎禉妋㶭揂獶汼羗汓䒒尣銹㕛䌊㔽䍃䂚䚻䬀唀瀀䀁蜏輏㤑脜丣怣㘥優怮逰㰶猶鈾䱂聈䅎㽕蕕㕗牗偤㹨酭牰㕱湵魷䑻貁憂䚃梄䢊㮋沋纋鮋羐嚘誘䆜㾞䢟㺠㒡莤䞥銪㚭庮岰䒴亴䖻㻀駀苃哊㫍䳑狛㓜㛜秞峟峳郵迶姷㳺滺䛻櫾糿栯㳛甴麕搧褎冘逌鴢訧輶鄾遊楢邎肬斿櫌泑狖懮怞") ("yu" "于与育余预域予遇语誉玉鱼雨渔裕谷愈娱欲吁舆宇羽逾豫郁寓狱喻御浴愉禹俞蔚榆愚渝尉淤虞屿峪粥驭瑜禺毓钰隅芋熨瘀迂煜昱|於臾畲盂聿竽萸妪腴圄谕觎揄龉谀俣馀庾妤瘐鬻欤腧鹬阏阈嵛雩鹆毹菀菸圉蜮伛纡窬窳饫蓣狳肀丿舁蝓燠玙彧堉嵎铻滪邘圫|㳚峿敔鄅悆鄃淯隃琟棫畬腘㺄矞缐瑀艅褕隩薁潏遹燏髃|澚䞝閼䓊湡䬛㳼䨁䧕㹼㫹䞕儥㵄㽳雽䛎䰥䋭糓䤋丂㧕蝺貗㤜鱊㭌桙㻰䱾氀䢖頨䘻䵥兪䩱䎉㪌㢏娪陓䬑㷉叞衘伃䬔䜡㤢㰲魣籲㚜㦽㧒䫻捓㮋㺠㻀䳑䴁漁㬂䬄䈅鰅紆鸆礇與㼌蘌輍欎䄏預䨒礖㠘䘘餘琙娛蘛欝䨞茟蜟騟䔡砡稢堣謣㤤欥錥㠨䄨嬩爩鴪戫匬堬萭鐭萮栯㬰茰㔱䘱霱鬱䐳逳焴㼶稶鈺䰻䜽輿䍂獄籅偊噊䁌鵌䥏㙑酑䩒癒鵒㥔㥚魚䉛扜鍝䍞籞歟楡㝢硢㽣祤㥥穥聥衧㑨䁩灪䵫齬畭睮㡰硲扵歶虶䱷蕷穻譽慾㪀媀㒁喅䖇䮇悇銉䂊芌嶎亐喐貐䢓斔䮙㦛㶛䂛㒜㺞澞語䲣螤㚥龥禦覦醧䢩袬骬馭㺮蒮傴䆷螸嶼庽鮽㲾閾䣁俁㣃迃軉䃋惐㷒盓雓䛕䋖嫗秗懙㳛棛諛鷠黦䗨飫忬諭櫲䏸鷸蓹毺俼篽鳿灹楀僪幙貍牏媮麌鋙捥藇顒瘉鸒礜鴥娯踰鬰崳唹杅饇歈驈魊蕍繘獝轝罭楰噳齵箊玗斞澦喩羭璵鋊緎寙棜旟淢釪緰惌") ("yuan" "元员院原源远愿园援圆缘袁怨渊苑冤媛猿垣沅塬垸鸳|辕鸢瑗圜爰芫鼋橼螈眢箢掾湲|妧焆涴蜎嫄薳羱|㼂䳁䟦輐䈠䝠䭴喛䣰㟲䝹䖤㱧㘣弲萲䲻䱲㛪渁渆䬇圎褑園圓渕鼘鴛謜鼝贠褤䬧猨㤪蜵逺䬼嬽灁獂轅㭇䅈剈㹉衏㥐遠䩩杬魭噮㥳葾傆邍禐溒蚖薗蒝榞貟䖠厡鶢榬蒬䲮鶰鎱妴媴厵䛄䛇駌䏍䳒櫞䳣緣囦棩裫㟶盶鳶裷鋺黿䡝隕䦾悁縁笎夗猭騵鹓願蝝蝯鵷円肙邧寃惌員淵") ("yue" "月说约越乐跃阅岳粤悦曰钥|栎曜钺樾瀹龠哕刖玥汋|骍焆彟趯爚籥|扚噦彠矆臒㯞㭾䆕䆢䟑樂攊檪櫟說哾䎳焥嬳䒸䬂䎀㧒約鑰㵸䋤藥黦鈅鸙㰛蘥㬦䤦㜧䠯㜰䥃籆䡇㹊鉞籰恱捳䢁枂䖃岄悅躍蚎蚏妜閱䢲䶳粵箹嶽跀䋐篗䟠泧曱矱髺楽擽鋭説軏戉鸑礿抈閲禴狘") ("yun" "员运云允孕蕴韵酝耘晕匀芸陨纭熨郧筠|恽韫郓氲殒愠昀狁鋆赟|沄妘涢缊榅筼煴蕰馧|煾頵㚞㷉叞輼緼㩈韗馻㒁贠蜵貟眃鄆蘊㜏輑鄖鈗紜縜䤞褞愪阭氳䨶耺夽饂運慍橒䉙䡝腪齳䵴䩵蝹荺蒀㚃枃暈傊䚋㞌抎蒕隕醖喗殞醞鶤玧䞫䆬䲰榲䪳䢵蒷㚺䦾秐䇖韞㟦囩賱惲雲藴緷勻韻餫涒員贇縕伝霣畇蕓奫薀熅熉澐枟溳磒篔") ("za" "杂扎砸咋匝|咂拶臜||囃噈䆘濽䦈㳨啑䣠䨿帀紮襍鉔魳䕹偺䞙䪞沞抸鮺嶻迊囐雜雥韴磼囋紥灒雑臢喒") ("zai" "在再灾载栽仔宰哉|崽甾||睵酨載儎㴓渽扗䵧㱰災侢傤㞨䮨䏁烖䣬賳䔂洅縡菑") ("zan" "赞暂咱攒|昝簪糌瓒錾趱拶臜|寁酂|䟃㨻噆䍼䗞䥄攅攢濽㔆㙻䬤䐶䭕䟅㳨鏩篸兓䍝㳫鐟䙉偺鐕儧簮㤰礸㜺鄼兂桚饡穳襸讃撍讚暫沯趲禶㣅瓉囋瓚㟛鏨㭮灒酇臢贊欑儹喒賛揝蹔") ("zang" "藏脏葬赃臧|奘戕驵牂臜||匨牫驡弉贓贜㘸塟鍺羘銺賍髒駔賘臟蔵臢臓") ("zao" "造早遭枣噪灶燥糟凿躁藻皂澡缫|蚤缲唣璪|惛慥簉|謲䒃㯥繰繅䖣䗢䜊唕艁䥣蹧鑿䲃梍㲧醩薻竃竈棗髞㿷喿譟皁傮趮") ("ze" "责则泽择侧咋啧|仄箦赜笮舴昃迮帻|䃎鲗|䔾荝側㥽厠廁矠嫧䯔㤞㢎伬襗㮣㚖簀樍禝䂝㟙㺓䟄䅚䔼㻭捑䶡鰂稄蠈蠌嘖昗夨耫謮蔶䰹汄則䕉幘齚䕪庂瞔皟澤䶦責溭㖽㳁擇諎䇥㣱㳻賾葃礋飵鸅謫灂泎齰睪唶崱萴択沢") ("zei" "贼||鲗|鯽鰂蠈㖽戝鱡賊") ("zen" "怎|谮||㻸譖撍譛䫈") ("zeng" "增曾赠憎|锃甑罾缯|鄫矰鬷|曽䇸䵴贈䰝譄繒驓䙢㽪璔綜熷鋥磳縡橧増") ("zha" "查扎炸诈轧闸渣蜡咋乍榨楂札栅眨咤|柞喳喋铡蚱吒砟揸痄哳齄膪拃|挓奓溠鲊䃎劄鲝霅齇|囃㯥䈟蔖䆛蕏藸㓃剳箚鰈㩹䮢䄍䢱䟻㔍㑵軋䀹搩齟䶥䱹蠟蝋䙄㞚㳐䮜㚫譇潳鞢䄰偞紮鮺耫諎㽪䞢䋏簎㴙樝紥謯甴踷蠿牐詐譗鍘䵙㱜䕢摣偧䵵䥷㡸灹㒀厏閘咜抯宱䖳皶皻㷢苲柵䛽䋾觰挿査喥箑煠搾鮓醡蚻柤") ("zhai" "债择宅寨侧摘窄斋祭翟|砦瘵膪|擿|㢎䓱䑲啇㟙齊亝䍉駘擇㒀厏礋齋鉙捚㩟㡯債榸飵厇檡抧骴択斎岝") ("zhan" "展战占站崭粘湛沾瞻颤詹斩盏辗绽毡栈蘸|觇旃谵骣搌拃|飐栴偡嵁嶦鹯鳣|䗞䳻䏼䐤顫㙴覘惉䧯䬤䵣㔊噡黵飦餰䩆碊閚鳽䁪譧㜊䈴㟻椫䆄䦅暫氈氊霑輚㠭戰䘺椾輾䡀䩅蹍橏驏佔魙䱠譠虦譫䁴䱼嶃嶄趈䪌榐䎒㺘嶘薝讝㞡斬覱綻䗃䟋䋎菚旜㟞盞棧㻵㣶嫸欃蛅儃襢怗鸇琖戦樿詀鉆轏蹔饘驙桟鱣虥呫邅醆颭皽") ("zhang" "长张章障涨掌帐胀彰丈仗漳樟账杖璋|嶂仉瘴蟑獐幛鄣嫜鸮|暲|㙊兏䩨镸弡㢓蔁礃餦瘬漲帳張脹騿扙慞㙣遧㕩㽴粀墇涱傽賬痮䛫長粻鱆瞕鞝麞") ("zhao" "着照招找召朝赵兆昭肇罩钊沼嘲爪|诏啁棹笊|柖鸼旐曌|㫤鼌䰫䄻䑲䧂㹿鳭窼爫佋㷹㑿鮡䖺䈃㨄䈇鉊詔䝖㕚䍜鍣䍮瑵㡽肁羄肈箌㺐䮓趙枛妱瞾盄䃍㷖釗狣菬燳巶雿啅皽鵫垗炤櫂駋") ("zhe" "这者着浙折哲蔗遮辙辄柘|锗褶蜇蛰鹧谪赭摺乇磔螫夂|晢啫喆詟䗖䗪|㸞㢎䆛袩轍䁤㯙䧪䋲㞼䮰䙷棏㰅潪㡳䊮聑㭯㫼㡇䂝䜆粍䀅䁋㭙懾㵊樜杔驝馲矺扸㦻軼鍺鸅䐑輒砓䠦謫䐲耴謺䝃䝕啠晣䵭虴襵籷歽䩾讁厇禇㞏讘䂞䊞嚞檡䎲銸㪿蟄蟅䓆瓋埑鷓烢嫬㯰䏳嗻㝂㙷慹淛䇽謶窾蹻屩悊輙這慴讋鮿") ("zhen" "镇真针圳振震珍阵诊侦臻贞枕桢赈祯帧甄斟缜箴疹|娠鸠砧榛揆鸩轸稹溱蓁胗椹朕畛浈|纼昣袗揕葴瑧瑱禛鬒|㭫䴾㨋鈂謓屒鍖敶㲀裖䀕湞䫃㱽鐤槇䡩竧䡅䪾沵䀼䠴䧵䚯鷆㛛枮鮝㼉紖榐蜄鴆笉挋栕栚縝縥㴨帪弫䨯㐱錱搸診堻樼幀鉁轃聄籈瑊䑐靕酙陣塦潧楨䝩祳偵晸絼禎蒖覙㪛媜殝貞䂦䂧蒧誫抮鎮侲㮳䪴䲴辴澵䊶㣀揁嫃㓄寊賑䏖針㯢軫䫬䳲䟴酖沴甽黮鉆眕眞眹紾獉遉桭鱵鍼抌碪鎭薽珎鷏黕駗姫黰") ("zheng" "政正证争整征郑丁症挣蒸睁铮筝拯桢帧峥|怔诤狰徵钲鲭|烝憕|脀崝㐼塣憆徎䆸䫆埥掟鯖鮏浧幀晸禎媜貞揁鬇鴊猙錚崢䈣踭鄭氶愸㽀佂聇證䥌㱏䡕睜㡠鉦㡧䥭抍箏掙䦛撜炡徰䦶䂻姃諍埩䛫鏳糽朾襼眐爭証癥徴篜") ("zhi" "制之治质职只志至指织支值知识直致执置止植纸智殖秩旨址滞氏枝芝脂帜汁肢挚稚酯掷峙炙栉侄芷窒咫吱趾|痔蜘郅桎雉祉郦陟痣蛭帙枳踯徵胝栀贽祗豸鸷摭轵卮轾彘觯絷跖埴夂黹忮骘膣踬沚祇扺|泜咥庤珪晊虒梽畤铚媞蔀跱锧稙滍禔榰疐擿蹢|䜠鵄遟汦歭傂淔䩢蹛㿃㥀㥁㜱䀸䱃摕潪䑭㡳墆䂡䏑䧝䟡㬪䘭眰䲀䞇㲳臷㫼剬鶨䃽謢䤠楖㡶鯯䪒瀄擳鳩摨䰴呮疷杫㾅䚇識䶡䖨銴㫑菭䝰嚔䣽璏䚳斦妷秇䘣㧗㧻䠦㯰䦛㨁倁褁嬂挃贄鼅䐈㘉輊帋砋漐洔㨖紙鴙㴛娡䌤椥儨訨礩鴩䐭騭搱鴲縶洷䬹䄺栺稺崻㜼聀䭁坁㝂䵂㕄䉅䑇驇䕌潌䥍祑豑豒織䉜幟䱥汥陦坧襧䱨䅩筫祬摯㙷䝷職䡹慹衼垁䞃禃憄䆈墌誌徏躑躓梔劕綕芖㲛徝覟袠庢䚦劧抧熫貭䦯膱螲隲馶㮹䎺疻隻馽䏄軄䳅瓆䟈㗌䓌櫍翐秓䫕秖䛗觗旘蟙鷙䇛櫛淛釞瓡藢觢駤㣥㗧姪質䏯滯擲秲巵胵觶執臸軹緻䇽淽製狾㛿䇧厓樲捗茞戠蚔瘈廌乿楺軽衹穉殢鉄阤讬碔疧埶扻搘猘値紩阯樴蘵騺恉鑕蹠偫遰犆銍厎厔袟胑鋕寘柣迣懥秪懫秷鳷") ("zhong" "中重种众终钟忠仲衷肿踵|冢盅忪锺舯螽夂|茽柊穜|褈祌蝩徸塜鼨㼿䳋銿螤瘇鐘蔠鈡刣鴤種堹㐺眾終煄偅乑幒筗塚籦潨腫䱰歱蹱衳衶汷鍾炂妐媑妕蚛喠㲴泈緟諥㣫鈆伀尰衆湩彸狆") ("zhou" "州周洲舟骤轴昼宙粥皱肘柚咒|帚胄绉啄纣妯啁诌繇碡籀驺酎荮㤘|㑇辀鸼婤椆赒鲖|㫶㹐㨶嚋薵㿒㥁㣙胕㝌㗙䔭䏔䓟翢䐌䭥俼謅驟諏㨄㲴洀紂㔌霌䐍縐輖㼙䈙伷鵃詋籒籕䩜晝噣葤呪晭睭㥮㑳銂䶇冑箒粙疛䖞徟㾭皺䎻䛆淍駎烐䋓珘賙鯞䇠㛩矪郮菷軸䐢紬詶鞚斨碻埶掫甃騆輈怞週譸喌侜咮盩诪僽") ("zhu" "主术住注助属逐著筑驻朱珠祝猪诸柱竹铸株瞩嘱贮煮烛苎褚蛛拄铢洙竺蛀渚伫杼|侏诛茱箸炷躅翥潴邾槠舳橥丶瘃麈疰|纻苧柷砫蠋|敱䫖蕏㶆䎝墸泏藸鯺䇬䳠䠼䐗䘄䪒逫磩鸀尌䠱術兪屬䆝薥迬嗻噣䇠軸笁鼄㔉霔㤖欘䘚笜眝䰞䬡䐢䘢爥樦瀦䌵紸鴸註蠾茿嵀鱁硃鑄䍆佇㝉孎㑏煑絑䝒鉒䭖罜灟㹥祩蝫䝬豬㵭䥮筯䕽坾劅誅麆莇趉宔銖㺛炢鮢劯貯䮱殶䎷㾻袾㫂䟉築濐駐囑跓諔矚竚䇡櫡㧣䇧櫧櫫篫燭曯駯觰飳壴軴諸秼㿾斀蠩跦篴跙藷芧珎朮紵詝陼窋劚羜馵斸蓫鋳") ("zhua" "抓挝爪||髽|膼撾檛簻") ("zhuai" "拽|||睉尵顡跩転") ("zhuan" "专转传赚砖撰篆沌|馔啭颛抟䏝|瑑僎|㙛㼷傳諯耑腞叀䚈䤄㛯孨䧘恮㑷䏙賺專甎堟鄟襈饌籑顓譔䡱䉵灷瑼蒃膞囀鷒磚蟤嫥竱篿篹剸転専縳鱄轉塼") ("zhuang" "装状庄壮撞妆幢汝桩|奘僮戆|漴|䚒湷贛戅戇弉樁焋娤梉莊妝狀糚裝壵獞泆荘粧壯") ("zhui" "追坠缀椎锥赘|惴隹骓缒|倕|䧳娷腄桘㝽㩾諈腏䋘䨺轛磓㚝㾽錗醀䢡㿢䃍贅騅礈縋䄌笍錐鴭娺錺鑆譵墜沝窡綴錣甀畷醊餟鵻硾膇") ("zhun" "准屯谆|肫窀圫|䐃衠|埻飩稕訰宒綧鶽諄凖啍旽準迍") ("zhuo" "着著缴桌卓捉赃琢灼浊酌拙茁涿|镯绌啄濯焯倬擢斫踔棹诼浞禚棁魆汋|叕椓晫燋|㧳䴵矠䙯䔲㲋䂐䮕趠䆯諁䃗䵠㹿㠚㒂籗繳捔穱䞵䏐㓸䟾狵䐁圴鉵聉蓔㧻蠿䵵䮓噣坧墌劅櫡娺窡錣鐯鐲丵謶琸㑁灂啅穛剢㭬罬籱䕴䅵硺斀䶂㺟炪㪬撯妰斱犳斵濁擆泎諑槕鋜烵㣿藋鵫蠗蝃彴斮斲梲鷟篧棳") ("zi" "资自子字咨滋仔姿紫兹孜淄籽梓鲻渍姊吱|秭恣甾孳訾滓锱鹚辎趑龇赀眦缁呲笫谘嵫髭茈粢觜耔嗞孖|虸洓鄑渟镃鼒|㠿㢀䆅䖪䦻㧘䴾㑵㬐齍䁒璾蓻㾅㞨蠀䔂吇䐉茊紎椔錙輜鴜茡㰣䘣栥鰦漬鈭崰茲倳稵㰷輺㜽頾訿頿䅆杍葘啙齜呰㱴孶湽鍿鶅禌芓榟趦㺭貲秄緇鯔姕㧗釨諮秶矷沝穧磒菑眥剚牸扻玆鎡澬鶿資姉胏胔胾") ("zong" "总综宗纵踪棕|粽鬃偬枞腙疭熜|倧鬷|樅錝鍯総鏓緫䙕䎫䁓䡯鑁䖲綜縂搃鬉倊䰌騌猔愡朡猣縦踨堫昮稯縱椶總㹅䝋嵏艐嵕䍟蝬捴嵸葼憁碂㢔骔熧緃糉㷓揔蓗惣磫糭鯮緵㯶鯼惾潨撦鍐騣瘲摠蹤豵傯翪") ("zou" "走邹奏|揍诌诹驺陬楱鄹鲰|飏|䅳齱䲀㞫謅鄒䠫騶㔿驟㵵齺箃媰黀諏鯫棷㔌赱掫緅菆郰棸") ("zu" "组族足祖租阻卒|俎诅镞嗾槭驵菹捽|岨珇砠崒疐|䬨鏃䃚㵀紣䙘㲋㩆葅箤伹稡鉃鉐趲駔䔃唨崪㰵爼踿組詛䱣蹵䅸靻鎐䖕䚝㲞蒩傶㞺㧻䯿錊謯伜顇籓怚踤卆哫柤邅") ("zuan" "钻赚纂攥|缵躜|敩|䰖㷪䡅饡䌣䤸鑚繤鑽纉䂎纘躦賺籑䉵篹儹揝籫") ("zui" "最罪嘴醉咀|羧蕞觜|衒槜|濢槯嗺䓱㵃酨嫢㭰稡欈䯿洅錊㰎㠑栬樶䘹絊㝡酻祽噿嶉嶊檌䮔纗嶵璻蟕鋷朘脧蕝睟酔晬檇厜辠墬") ("zun" "尊遵|鳟樽撙|僔僎噂嶟|袸䔿拵罇譐鱒繜銌鷷栫瀳跧鐏捘墫壿") ("zuo" "作做座左坐昨佐馈琢凿撮祚|柞唑嘬酢怍笮砟阼胙捽|岞|侳䟶䬤㶡䦈㩇䟄䩦䟭㤰㘸䜊鑿諎䇥㣱唨䯿㘀夎稓䔘㸲㘴鈼葃㑅繓䝫㭮㝾袏咗䞢䎰䞰䋏毑㛗秨糳飵莋椊葄筰岝")) "拼音汉字对照表. 第一个元素为拼音,第二个元素为拼音对应的汉字组成的字符串,字符串 中汉字按照使用频率排序,字符串用 “|” 隔开,分成一级常用汉字,二级 常用汉字,三级常用汉字和不常用汉字。分类方式参考了国务院公布的 《通用规范汉字表》: 国务院关于公布《通用规范汉字表》的通知(国发〔2013〕23号) http://www.gov.cn/zwgk/2013-08/19/content_2469793.htm 但不是完全一致。") (defvar pyim-pymap-duoyinzi-chars '(("a" "阿") ("ai" "艾") ("ao" "坳") ("ba" "扒") ("bai" "柏") ("bang" "磅") ("bao" "薄" "曝" "暴" "堡" "剥" "刨") ("beng" "蚌" "泵") ("bi" "裨" "臂") ("bian" "扁" "匾" "便") ("bo" "伯" "泊") ("bu" "卜" "不") ("can" "参") ("cang" "藏") ("ce" "侧") ("ceng" "曾") ("cha" "查" "差") ("chai" "拆") ("chan" "禅" "掺") ("chang" "厂" "长") ("chao" "嘲" "朝") ("che" "辙" "车") ("cheng" "乘" "称" "橙" "澄") ("chi" "尺") ("chou" "臭" "仇") ("chuan" "传") ("chuo" "绰") ("ci" "伺") ("da" "大") ("dai" "呆") ("dan" "单" "弹") ("dao" "叨") ("de" "的" "得") ("di" "底" "地") ("diao" "调") ("ding" "丁") ("dong" "洞") ("dou" "都") ("du" "读" "度") ("dun" "顿" "蹲" "沌" "敦") ("duo" "堕") ("e" "恶") ("fan" "繁" "番") ("feng" "冯") ("fo" "佛") ("fou" "否") ("ga" "旮") ("gai" "盖") ("gang" "扛") ("gao" "镐") ("ge" "革" "铬" "蛤") ("gei" "给") ("gong" "汞") ("gou" "枸") ("gu" "谷") ("gua" "括" "呱") ("guan" "莞") ("guang" "广") ("gui" "龟" "柜") ("hang" "夯") ("hao" "蒿") ("he" "菏" "核" "和" "呵" "合") ("hei" "嘿") ("hong" "虹" "红") ("hu" "鹄" "浒") ("hua" "划") ("huai" "徊") ("huan" "还") ("hui" "会") ("hun" "荤") ("huo" "豁") ("ji" "藉" "缉" "稽" "祭" "瘠" "亟") ("jia" "贾" "家" "夹" "伽" "价") ("jian" "见") ("jiao" "脚" "缴" "角") ("jie" "芥" "秸" "解") ("jin" "劲") ("jing" "颈" "荆") ("ju" "桔" "咀" "句") ("jue" "jiao" "觉") ("jun" "浚") ("ka" "咖" "卡") ("kai" "楷") ("kan" "槛") ("kang" "亢") ("ke" "坷" "咳") ("keng" "吭") ("kui" "馈" "溃" "匮") ("la" "蜡" "腊") ("lao" "烙" "姥") ("le" "勒" "了" "乐") ("lei" "肋") ("lin" "赁") ("ling" "棱") ("liu" "六") ("lu" "陆" "碌") ("luo" "络" "落") ("lv" "缕" "绿" "率") ("mai" "脉" "埋") ("mang" "氓") ("mao" "冒") ("me" "么") ("mei" "酶" "没") ("meng" "萌") ("mi" "谜" "秘" "泌") ("mian" "娩") ("miu" "缪") ("mo" "模" "摩" "抹") ("mou" "牟") ("mu" "沐") ("na" "那" "哪" "呐") ("nan" "南") ("ne" "呢") ("ni" "溺") ("niao" "鸟" "尿") ("nong" "弄") ("nuo" "娜") ("nve" "疟") ("pan" "ban" "扳") ("pang" "膀" "胖" "旁") ("pao" "炮") ("pi" "辟") ("pin" "拚") ("ping" "屏") ("po" "魄" "迫") ("pu" "璞" "莆" "脯" "瀑" "朴" "埔") ("qi" "骑" "蹊" "栖" "期" "契" "其" "奇") ("qian" "乾" "铅" "茜" "浅" "嵌" "堑") ("qiang" "强") ("qiao" "荞") ("qie" "且" "茄") ("qin" "亲") ("qu" "区") ("quan" "券" "圈") ("que" "雀") ("sai" "塞") ("sao" "缫") ("se" "色") ("sha" "莎" "厦") ("shan" "杉") ("shang" "裳") ("she" "赊" "蛇" "摄") ("shen" "莘" "沈" "参" "什") ("sheng" "盛" "省") ("shi" "食" "适" "识" "石" "氏") ("shu" "熟" "漱" "术" "数" "戌" "属") ("shuai" "衰" "率") ("shui" "谁") ("shuo" "说") ("si" "似") ("su" "宿") ("suo" "缩" "梭") ("tang" "汤" "倘") ("tao" "陶") ("ti" "提") ("ting" "铤" "烃") ("tui" "褪") ("tun" "屯" "囤") ("tuo" "拓" "沱") ("wan" "万") ("wang" "亡") ("wei" "蔚" "圩") ("wo" "涡" "挝") ("wu" "鹜" "无") ("xi" "铣" "洗" "戏" "系") ("xia" "虾" "吓") ("xian" "癣" "县") ("xiang" "降" "巷") ("xiao" "嚣" "削" "校") ("xie" "邪" "挟" "偕") ("xing" "行") ("xu" "嘘" "许") ("xue" "血") ("xun" "寻") ("yan" "腌" "咽") ("yao" "钥" "窑" "侥") ("ye" "曳" "叶") ("yi" "遗") ("yin" "殷") ("yong" "甬") ("you" "柚") ("yu" "尉" "吁") ("yuan" "员") ("yue" "约") ("yun" "蕴" "熨") ("za" "咋") ("zai" "仔") ("zang" "赃" "臧") ("zao" "皂") ("ze" "择") ("zha" "楂" "栅" "扎") ("zhan" "辗" "斩") ("zhao" "召") ("zhe" "着" "折") ("zhi" "炙" "殖" "挚" "峙" "吱") ("zhong" "种" "重") ("zhou" "粥") ("zhu" "著") ("zhua" "爪") ("zhuai" "拽") ("zhuan" "赚") ("zhui" "缀" "椎") ("zhuo" "琢") ("zi" "兹") ("zu" "卒")) "多音字最常用的读音。") (defvar pyim-pymap-duoyinzi-words '(("a" "吖啶" "腌臜") ("ang" "张卬") ("ao" "拗口" "拗陷") ("ba" "峇厘") ("bai" "伯特" "伯琮" "伯颜" "叔伯") ("ban" "扳动" "扳回" "扳子" "扳平" "扳手" "扳机") ("bang" "彩蚌" "翅膀" "肩膀" "膀子" "膀臂" "臂膀") ("bao" "龅牙") ("bei" "孛星" "摇臂" "断臂" "月孛" "胳臂") ("bi" "俾使" "俾倪" "刘辟" "吡啶" "复辟" "泌阳" "睥睨" "秕子" "秕糠" "秘鲁" "豆皀" "贲临" "辟邪") ("biao" "嘌呤") ("bin" "刘玢" "槟城" "槟子" "香槟") ("bing" "主屏" "屏息" "屏气" "屏除" "槟州" "槟榔") ("bo" "丝柏" "刻薄" "剥削" "剥啄" "剥夺" "剥掉" "剥皮" "剥离" "剥落" "剥蚀" "单薄" "厌薄" "巨擘" "微薄" "摊薄" "擘开" "擘画" "柏林" "浅薄" "淡薄" "稀薄" "绵薄" "萝卜" "薄产" "薄利" "薄厚" "薄命" "薄地" "薄幸" "薄弱" "薄待" "薄情" "薄技" "薄明" "薄晓" "薄暗" "薄暮" "薄海" "薄田" "薄礼" "薄膜" "薄荷" "薄酬" "薄雾" "薄面" "超薄" "轻薄" "鄙薄") ("bu" "吴堡" "堡寨" "堡的" "大埔" "安瓿" "座堡" "米堡") ("ca" "喀嚓" "拆毁") ("cen" "参差") ("cha" "刹那" "咔嚓" "喀嚓" "梵刹" "罗刹") ("chai" "交差" "信差" "出差" "差事" "差旅" "差派" "差遣" "支差" "邮差") ("chan" "单于" "惊颤" "震颤" "颤动" "颤抖" "颤栗") ("chang" "裳凤" "週長" "霓裳") ("chao" "征剿") ("chen" "不称" "匀称" "可称" "后称" "对称" "抻面" "沈积" "沈重" "沈默" "相称" "称多" "称德" "称心" "称是" "称职" "称臣") ("cheng" "丁盛" "之盛" "刘晟" "李晟" "盛的" "祐樘" "称稱" "饼铛") ("chi" "一匙" "汤匙" "茶匙" "豆豉") ("chong" "三重" "二重" "双重" "多重" "李重" "艨艟" "辎重" "重传" "重估" "重修" "重做" "重写" "重印" "重发" "重叠" "重合" "重名" "重启" "重回" "重围" "重塑" "重复" "重审" "重庆" "重建" "重开" "重拍" "重拾" "重振" "重播" "重整" "重新" "重来" "重构" "重温" "重演" "重点" "重现" "重生" "重用" "重申" "重的" "重组" "重罚" "重置" "重获" "重装" "重覆" "重评" "重试" "重读" "重赛" "重蹈" "重载" "重返" "重造" "重逢" "重重" "重门" "重阳") ("chu" "人畜" "仔畜" "公畜" "家畜" "李柷" "牧畜" "牲畜" "畜力" "畜栏" "畜牲" "畜生" "畜禽" "畜类" "畜肥" "禽畜" "耕畜" "褚遂") ("chuai" "啜饮" "搋子" "搋面") ("chun" "鹌鹑") ("ci" "兹的" "参差" "鸬鹚") ("cong" "单枞" "厚熜" "枞树") ("cu" "卒于" "吏卒" "士卒" "戍卒") ("cuan" "拼攒") ("cui" "衰变") ("cuo" "公撮" "妄撮" "撮合") ("dai" "大夫" "大黄") ("dan" "王赡" "脏彈" "黄疸") ("dang" "铃铛") ("de" "代地" "似地" "其地" "北地" "地与" "地为" "地做" "地向" "地听" "地在" "地委" "地学" "地对" "地将" "地底" "地把" "地村" "地用" "地的" "地矿" "地置" "地说" "地走" "多地" "少地" "市地" "汉地" "猛地" "的地" "目地" "般地") ("dei" "之得" "也得" "习得" "你得" "又得" "就得" "得之" "得先" "得其" "得去" "得多" "得太" "得好" "得宠" "得很" "得最" "得有" "必得" "总得" "我得" "真得" "而得" "还得" "都得" "非得") ("deng" "澄清" "真澄" "高澄") ("di" "中的" "宝坻" "寻的" "打的" "提溜" "提防" "标的" "的士" "的确" "目的" "美的" "面的") ("dian" "佃农") ("die" "喋喋") ("ding" "樱町" "畹町" "虰蛵") ("dong" "侗族" "恫吓" "杨侗" "硐室") ("dou" "句读") ("du" "上都" "下都" "东都" "中都" "丰都" "为都" "之都" "乐都" "于都" "京都" "他都" "们都" "军都" "副都" "南都" "古都" "后都" "商都" "国都" "大都" "天都" "奠都" "宁都" "宇都" "安都" "宗都" "官都" "定都" "帝都" "建都" "德都" "性都" "成都" "故都" "文都" "新都" "昌都" "望都" "武都" "江都" "留都" "的都" "皇都" "等都" "臣都" "花都" "计都" "迁都" "都会" "都兰" "都匀" "都城" "都山" "都市" "都护" "都昌" "都是" "都有" "都灵" "都的" "都督" "都等" "都统" "都要" "首都") ("duo" "哆啦" "哆嗦" "审度" "揣度" "驮子") ("e" "东阿" "吟哦" "哦哦" "噁嗪" "噁心" "蛾类" "阿堵" "阿胶" "阿谀" "阿附" "阿难" "飞蛾") ("ei" "诶笑" "诶诒") ("en" "嗯啊" "嗯嗯") ("fa" "砝码" "酦酵") ("fei" "米芾") ("fen" "刘玢" "坋粒" "焚书" "焚毁" "焚烧" "自焚") ("feng" "焚书") ("fu" "仿佛" "果脯") ("ga" "伽马" "呷呷" "咖喱") ("gai" "芥兰" "芥蓝" "蓋兹") ("gan" "乾癣" "乾道" "孙乾" "承乾" "烘乾") ("ge" "咯咯" "回纥" "袼褙") ("gu" "回鹘" "鸿鹄") ("gua" "蜗牛") ("gui" "王珪" "鲑鱼" "鳜鱼") ("guo" "涡阳" "絮聒" "聒噪" "聒耳") ("ha" "虾夷" "蛤蟆" "蛤蟹") ("hai" "上还" "中还" "也还" "人还" "他还" "但还" "你还" "倒还" "却还" "她还" "它还" "宗还" "帝还" "您还" "我还" "放还" "谁还" "还不" "还为" "还以" "还会" "还像" "还剩" "还去" "还叫" "还可" "还和" "还在" "还多" "还大" "还好" "还嫌" "还对" "还将" "还小" "还少" "还差" "还带" "还应" "还很" "还得" "还快" "还怕" "还想" "还找" "还把" "还挺" "还敢" "还早" "还是" "还曾" "还有" "还望" "还未" "还来" "还没" "还玩" "还用" "还看" "还真" "还算" "还给" "还能" "还行" "还被" "还要" "还让" "还说" "还请" "还贵" "还远" "还问" "还需" "还须" "还高" "这还" "那还" "里还") ("hang" "一行" "世行" "两行" "中行" "交行" "人行" "内行" "农行" "几行" "分行" "同行" "商行" "在行" "外行" "太行" "央行" "巡行" "工行" "建行" "总行" "懂行" "我行" "投行" "招行" "换行" "排行" "支行" "改行" "本行" "桁杨" "每行" "港行" "生行" "行业" "行中" "行会" "行列" "行在" "行家" "行市" "行幸" "行当" "行情" "行数" "行的" "行省" "行署" "行营" "行规" "行货" "行长" "该行" "跨行" "车行" "转行" "这行" "银行" "闵行") ("hao" "蚝油" "貉子" "貉绒" "镐京") ("he" "上颌" "下颌" "吓声" "回纥" "威吓" "恐吓" "恫吓" "无颌" "有颌" "阖家" "阖庐" "阖闾" "隔阂") ("heng" "桁架" "桁梁" "道行") ("hu" "丝核" "吓唬" "和牌" "回鹘" "核菌" "菌核" "诈唬") ("huan" "朱鹮" "苋菜") ("hui" "秦桧" "讌會") ("hun" "珲春") ("huo" "上和" "为和" "义和" "书和" "会和" "值和" "元和" "克和" "党和" "兽和" "军和" "力和" "又和" "和一" "和三" "和不" "和与" "和东" "和两" "和中" "和之" "和二" "和亲" "和以" "和伊" "和元" "和党" "和六" "和其" "和分" "和刘" "和副" "和北" "和反" "和可" "和合" "和后" "和周" "和唐" "和在" "和外" "和多" "和大" "和嫔" "和对" "和小" "和州" "和帕" "和帝" "和张" "和文" "和新" "和晋" "和暖" "和更" "和最" "和有" "和本" "和李" "和村" "和杰" "和梁" "和王" "和的" "和省" "和秦" "和等" "和红" "和罗" "和萧" "和被" "和西" "和议" "和赵" "和辽" "和队" "和陈" "和非" "和马" "和高" "团和" "国和" "在和" "城和" "夫和" "奖和" "子和" "字和" "孙和" "孝和" "宗和" "官和" "室和" "家和" "寨和" "将和" "局和" "岩和" "州和" "年和" "庄和" "廷和" "性和" "感和" "成和" "战和" "戚和" "所和" "拌和" "搀和" "搅和" "斯和" "是和" "暖和" "机和" "权和" "条和" "林和" "梗和" "氏和" "求和" "汉和" "法和" "清和" "灯和" "特和" "王和" "田和" "的和" "福和" "税和" "组和" "罗和" "罪和" "者和" "营和" "部和" "险和") ("ji" "供给" "光奇" "奇偶" "奇尼" "奇数" "奇羡" "奇袭" "扶箕" "畚箕" "箕子" "簸箕" "给与" "给予" "给付" "给水" "自给" "补给") ("jia" "沦浃" "茄克" "雪茄") ("jian" "槛车" "轩槛") ("jiang" "下降" "不降" "倔强" "再降" "升降" "天降" "强嘴" "归降" "招降" "沉降" "空降" "被降" "起降" "迫降" "降下" "降世" "降临" "降为" "降价" "降低" "降到" "降压" "降哥" "降噪" "降将" "降幅" "降息" "降水" "降清" "降温" "降生" "降福" "降级" "降职" "降至" "降落" "降解" "降雨" "降雪" "霜降") ("jiao" "一觉" "侥幸" "倒嚼" "剿匪" "剿灭" "包剿" "午觉" "咬嚼" "围剿" "好觉" "审校" "征剿" "懒觉" "校准" "校勘" "校对" "校正" "校的" "校订" "校阅" "校验" "检校" "清剿" "温峤" "睡觉" "觉觉" "调校" "追剿") ("jie" "仓颉" "慰藉" "桔梗" "盘诘" "蕴藉" "藉口" "藉着") ("jin" "矜持" "骄矜") ("jing" "刘晟" "刚劲" "劲卒" "劲吹" "劲射" "劲峭" "劲急" "劲拔" "劲挺" "劲敌" "劲旅" "劲烈" "劲爆" "劲直" "劲草" "劲风" "强劲" "李晟" "箐村") ("jiong" "何炅") ("ju" "莴苣" "趑趄") ("juan" "垫圈" "猪圈") ("jue" "主角" "名角" "咀嚼" "张角" "角力" "角抵" "角斗" "角色" "角逐" "角闪" "角阙" "配角") ("jun" "朱隽" "溥儁" "象龟") ("kang" "扛着") ("kao" "犒劳") ("ke" "借壳" "壳口" "壳子" "壳幔" "壳牌" "壳虫" "壳阶" "外壳" "弹壳" "机壳" "空壳" "脑壳" "蛋壳" "贝壳" "龟壳") ("kuai" "会计" "财会") ("kui" "傀儡" "隗嚣") ("kuo" "包括" "囊括" "总括" "括号" "括弧" "括毒" "括线" "概括" "综括" "赵括") ("la" "世㻋" "落下") ("lang" "莨菪" "阆中") ("lao" "落汗") ("le" "中肋") ("lei" "世㻋" "勒姆" "勒紧" "勒莫" "富勒" "帕勒" "福勒") ("leng" "棱台" "棱柱" "棱角" "棱锥" "棱镜" "模棱" "穆棱" "绥棱") ("lia" "他俩" "俩人" "咱俩" "我俩" "这俩") ("liang" "伎俩" "咱俩" "技俩" "雅靓" "靓丽" "靓仔" "靓女" "靓妹" "靓照" "靓颖") ("liao" "不了" "了了" "了事" "了却" "了得" "了断" "了然" "了结" "了解" "多了" "得了" "明了" "未了" "末了" "潦倒" "潦草" "知了" "罢了" "蓼蓝") ("lin" "拎着") ("liu" "常陆" "水陆" "陆凯" "陆励" "陆贽") ("long" "泷泽" "泷船") ("lou" "泄露" "露出" "露脸" "露面" "露馅") ("lu" "不露" "六合" "六安" "出露" "初露" "吐露" "外露" "寒露" "展露" "带露" "披露" "揭露" "显露" "暴露" "曝露" "梦露" "泄露" "泻露" "流露" "甘露" "白露" "蔗露" "蜜露" "表露" "裸露" "败露" "透露" "陈露" "雨露" "霜露" "露体" "露出" "露台" "露天" "露宿" "露水" "露点" "露珠" "露茜" "露营" "露西" "露露" "露面" "露韩" "露骨" "面露") ("luan" "娈童") ("lun" "丙纶" "涤纶" "绦纶" "腈纶") ("luo" "漯河") ("lv" "棕闾" "阖闾") ("ma" "干麼" "干麽" "抹布") ("man" "埋入" "埋怨" "滋蔓" "苏蔓" "蔓延" "蔓草" "蔓菁" "藤蔓") ("mang" "巨蟒" "蟒蛇") ("mao" "玳瑁" "铆工" "铆接" "铆钉") ("me" "什麼" "什麽" "这麼" "这麽" "那麽") ("mei" "谜儿") ("mi" "糜烂") ("mian" "渑池") ("mo" "出没" "吞没" "埋没" "嬷嬷" "沉没" "没收" "没药" "没落" "沦没" "浸没" "淹没" "潜没" "覆没" "隐没") ("mu" "姥爷" "模具" "模板" "模样" "牟平" "牟羽" "超模") ("na" "丽娜" "厉娜" "多娜" "娜娜" "娜的" "安娜" "李娜" "狄娜" "王娜" "琳娜" "谢娜") ("nao" "孬种") ("ne" "哪吒" "声呐") ("nei" "那个" "那位" "那台" "那天" "那家" "那张" "那次" "那种" "那边") ("ni" "去呢" "呢喃") ("nian" "粘土" "粘帖" "粘度" "粘性" "粘液" "粘痰" "粘稠" "粘粘" "粘胶" "粘膜" "粘贴" "胶粘") ("nie" "蘖枝") ("niu" "执拗") ("nu" "内帑") ("o" "你哦" "哦哟" "哦哦" "好哦") ("pa" "枇杷" "钉耙") ("pan" "拚命" "拚弃" "番禺" "番莲") ("pang" "彷徨" "牛蒡" "磅礴") ("pao" "龅牙") ("pei" "碳碚") ("pi" "蚍蜉") ("pian" "便与" "便便" "便宜" "便由" "扁壶") ("piao" "朴茨" "王朴") ("pie" "苤蓝") ("ping" "冯保" "冯剑" "冯异") ("po" "朴子" "朴茨" "泊头" "湖泊" "王朴") ("pu" "堡寨" "堡的" "座堡" "曝光" "曝露" "米堡") ("qi" "会稽" "侦缉" "槭木" "焉耆" "荸荠" "菜畦" "蒲圻" "鮨科") ("qia" "博卡" "卡洛" "卡的" "卡迪" "卡队" "和卡" "哨卡" "尔卡" "洛卡" "的卡" "菲卡" "髂骨") ("qian" "光纤" "犍为" "纤夫" "纤纤" "蕁麻") ("qiang" "戕害" "箐村" "羟基" "自戕") ("qiao" "冰橇" "刀鞘" "叶鞘" "地壳" "壳口" "壳牌" "壳虫" "壳质" "壳阶" "温峤" "甲壳" "躯壳" "雀子" "雪橇" "鞘脂" "髓鞘") ("qing" "亲家" "箐村" "血亲") ("qiu" "仇和" "仇士" "象龟") ("qu" "區旗" "蠼螋") ("que" "乙炔") ("rao" "刍荛" "桡骨" "阻桡") ("ru" "汝南" "汝城" "汝州" "汝阳") ("sa" "灑脱") ("sai" "鳃裂") ("se" "充塞" "出塞" "堵塞" "塞罗" "填塞" "拥塞" "搪塞" "杜塞" "栓塞" "梗塞" "淤塞" "血塞" "闭塞" "阻塞" "鼻塞") ("sha" "上杉" "刹住" "刹把" "刹车" "手刹") ("shai" "套色" "本色" "色子" "褪色") ("shan" "人单" "光栅" "单县" "单发" "单桨" "单生" "单福" "单超" "受禅" "封禅" "掸邦" "栏栅" "格栅" "王赡" "的单" "禅位" "禅定" "禅寺" "禅让" "赡养") ("shang" "羹汤") ("shao" "召入" "召到" "召来" "叶鞘" "杓子") ("she" "和折" "折可" "折本" "折秤" "折耗" "折钱" "歙县" "畲族" "瞽阇" "阇梨") ("shei" "是谁" "有谁" "谁也" "谁人" "谁会" "谁又" "谁家" "谁就" "谁是" "谁有" "谁来" "谁的" "谁知" "谁能" "谁要" "谁让" "谁说" "谁都") ("shen" "妊娠" "桑椹") ("sheng" "刘晟" "李晟") ("shi" "乌什" "什叶" "什邡" "似地" "似的" "喀什" "奥什" "好似" "布什" "殖质" "波什" "繁峙" "纳什" "腐殖" "豆豉" "通什" "钥匙") ("shou" "常熟" "成熟" "煮熟" "熟语" "腐熟") ("shu" "數周" "腧穴") ("shuang" "泷水") ("shui" "游说" "说客" "说服") ("si" "伺服" "伺机" "伺隙" "同食" "服食" "食材" "食邑") ("sou" "咳嗽") ("su" "李愬") ("sui" "尿样" "扶绥" "晋绥" "浽溦" "绥中" "绥化" "绥宁" "绥德" "绥棱" "绥江" "绥滨" "绥蒙" "绥阳" "绥靖") ("suo" "羧基" "羧酸") ("ta" "拓印" "拓片" "拖沓" "杂沓" "蛋挞" "鞭挞") ("tan" "乱弹" "动弹" "反弹" "弹出" "弹力" "弹劾" "弹匣" "弹压" "弹唱" "弹奏" "弹射" "弹性" "弹拨" "弹指" "弹斥" "弹牙" "弹琴" "弹簧" "弹纠" "弹花" "弹词" "弹跳" "手弹" "枪弹" "难弹") ("tang" "祐樘") ("tao" "临洮" "洮南") ("tiao" "上调" "下调" "不调" "区调" "协调" "可调" "回调" "失调" "宫调" "征调" "微调" "汉调" "烹调" "特调" "空调" "联调" "调价" "调休" "调低" "调侃" "调停" "调养" "调到" "调制" "调剂" "调匀" "调味" "调和" "调回" "调处" "调好" "调性" "调情" "调戏" "调成" "调控" "调教" "调整" "调料" "调来" "调校" "调温" "调理" "调的" "调皮" "调羹" "调至" "调节" "调解" "调试" "调速" "调配" "调门" "调队" "调音" "调频" "调驯" "调高") ("tie" "呫哔" "呫嗫" "呫毕" "嗫呫") ("ting" "室町" "樱町") ("tong" "杨侗" "洪洞") ("tou" "骰子") ("tun" "褪绿" "褪色") ("tuo" "驮兽") ("wan" "苏蔓" "莞尔") ("wei" "上尉" "中尉" "卫尉" "太尉" "尉氏" "少尉" "廷尉" "校尉" "浽溦" "都尉" "隗嚣") ("wen" "李玟") ("weng" "蕹菜") ("wo" "喔喔" "耳蜗" "蜗居" "蜗庐" "蜗旋" "蜗牛" "蜗蜒" "蜗行") ("wu" "厌恶" "可恶" "唔好" "唔知" "唔系" "嫌恶" "恨恶" "憎恶") ("xi" "勐腊" "栖霞" "水螅" "的腊" "腊味" "露茜" "鸂鶒") ("xia" "厦华" "厦大" "厦门" "陜西") ("xian" "光纤" "化纤" "安閒" "秋狝" "纤体" "纤小" "纤巧" "纤度" "纤弱" "纤毛" "纤细" "纤维" "纤芯" "苋菜" "閒暇" "閒混" "閒话" "閒谈") ("xiang" "李愬") ("xie" "仓颉" "便血" "出血" "吐血" "吸血" "的血") ("xin" "奕䜣" "莘庄") ("xing" "井陉" "反省" "省亲" "省察" "省悟" "省视" "自省" "荥阳") ("xiu" "一宿" "参宿" "宿命" "宿存" "星宿") ("xu" "丙戌" "壬戌" "庚戌" "戊戌" "戌狗" "牧畜" "甲戌" "畜牧") ("xuan" "乾癣") ("xue" "削减" "削去" "削夺" "削平" "削弱" "削职" "削藩" "剥削" "噱头" "戏谑" "瘦削" "磨削" "谐谑" "谑剧" "谑戏" "谑语") ("xun" "张浚" "毒蕈" "荨麻" "香蕈") ("ya" "倾轧" "枝桠" "琅琊" "轧场" "轧染" "轧棉") ("yan" "刘縯" "屋檐" "抽菸" "湮灭" "芫荽" "菸硷" "菸碱" "菸蒂") ("yang" "张卬") ("yao" "么点" "对幺" "幺二" "星曜" "约塔" "钟繇" "锺繇") ("ye" "呜咽" "哽咽" "琅玡" "琅琊" "琅邪") ("yin" "吲哚" "湮灭" "牙龈" "齿龈") ("ying" "荥经") ("you" "钟繇") ("yu" "俞夏" "蔚县") ("yuan" "胡芫" "芫花" "雇員") ("yue" "乐之" "乐器" "乐团" "乐坛" "乐工" "乐师" "乐府" "乐手" "乐曲" "乐清" "乐章" "乐经" "乐谱" "乐迷" "乐队" "乐音" "哀乐" "器乐" "国乐" "声乐" "奏乐" "密钥" "弦乐" "民乐" "爱乐" "礼乐" "胡乐" "配乐" "钟乐" "阎乐" "雅乐" "音乐") ("yun" "筠连") ("za" "包扎" "塔扎" "扎囊" "腌臜") ("zai" "甾酮") ("zan" "攒钱" "积攒") ("zang" "地藏" "宝藏" "川藏" "援藏" "搜藏" "滇藏" "玄奘" "藏人" "藏区" "藏文" "藏族" "藏民" "藏独" "藏獒" "藏羚" "藏语" "西藏" "进藏" "道藏" "青藏") ("zao" "凿井" "凿子" "凿枘" "凿空" "开凿" "榫凿" "确凿") ("zeng" "中曾" "他曾" "克曾" "曾哥" "曾孙" "曾山" "曾巩" "曾布" "曾祖" "曾随" "特曾" "还曾") ("zha" "冷轧" "柞水" "热轧" "轧制" "轧机" "轧钢") ("zhai" "祭天" "祭礼" "翟凌") ("zhan" "呫吨" "粘在" "粘贴" "粘连") ("zhang" "不长" "乡长" "了长" "二长" "会长" "信长" "兄长" "光长" "军长" "刘长" "助长" "区长" "厂长" "厅长" "县长" "台长" "司长" "团长" "园长" "在长" "增长" "处长" "外长" "大长" "学长" "家长" "尊长" "局长" "州长" "市长" "师长" "年长" "庆长" "店长" "庭长" "总长" "成长" "或长" "所长" "排长" "斜长" "旅长" "族长" "机长" "村长" "校长" "次长" "水长" "消长" "滋长" "状长" "班长" "生长" "的长" "省长" "社长" "科长" "站长" "等长" "组长" "至长" "舰长" "船长" "色长" "营长" "行长" "见长" "警长" "议长" "财长" "车长" "连长" "道长" "部长" "酋长" "镇长" "长了" "长兄" "长兼" "长冈" "长出" "长到" "长势" "长史" "长吏" "长圆" "长在" "长大" "长女" "长姊" "长子" "长孙" "长官" "长庆" "长得" "长成" "长毛" "长满" "长片" "长的" "长相" "长着" "长老" "长者" "长而" "长肉" "长胖" "长辈" "长进" "长高" "队长" "院长" "馆长" "首长") ("zhao" "一朝" "上朝" "不着" "了朝" "今朝" "入朝" "历朝" "嘲哳" "失着" "宗朝" "当朝" "得着" "找着" "早朝" "明朝" "朝之" "朝会" "朝夕" "朝政" "朝时" "朝晖" "朝有" "朝气" "朝的" "朝臣" "朝见" "朝贡" "朝阳" "朝霞" "李朝" "来朝" "爪哇" "爪牙" "的朝" "着凉" "着忙" "着急" "着想" "着慌" "着手" "着法" "着火" "着紧" "着落" "着边" "着迷" "着陆" "着魔" "睡着" "累朝" "视朝" "辽朝" "金朝" "阮朝" "陈朝") ("zhe" "故辙" "没辙" "苏辙" "褶皱" "覆辙") ("zheng" "魏徵") ("zhi" "月氏" "标识" "栉比" "王珪" "魏徵") ("zhou" "钟繇") ("zhu" "白术" "苎麻" "褚遂") ("zhuan" "传位" "传略" "传至" "传记" "传赞" "侠传" "假传" "列传" "前传" "史传" "外传" "小传" "左传" "盛馔" "自传" "记传" "重传") ("zhuang" "一幢") ("zhun" "家屯" "屯兵" "屯村" "屯田" "驻屯") ("zhuo" "免缴" "剥啄" "吸着" "扣缴" "执着" "沉着" "着力" "着墨" "着处" "着实" "着床" "着想" "着意" "着手" "着棋" "着眼" "着笔" "着色" "着落" "着装" "着重" "着陆" "穿着" "缴销" "衣着" "身着" "附着" "预缴" "黏着") ("zi" "产仔" "仔姜" "仔猪" "仔畜" "仔细" "华仔" "狗仔") ("zong" "厚熜" "枞阳") ("zu" "菹醢" "顇奴") ("zuan" "赚钱") ("zuo" "枘凿" "琢磨" "酬酢")) "多音字对应的词组。") (defvar pyim-pymap--py2cchar-cache1 nil "拼音查汉字功能需要的变量. 类似: \"a\" -> (\"阿啊呵腌|嗄吖锕||錒\")") (defvar pyim-pymap--py2cchar-cache2 nil "拼音查汉字功能需要的变量. 类似: \"a\" -> (\"阿\" \"啊\" \"呵\" \"腌\" \"|\" \"嗄\" \"吖\" \"锕\" \"|\" \"|\" \"錒\" \"\")") (defvar pyim-pymap--py2cchar-cache3 nil "拼音查汉字功能需要的变量. 类似: \"a\" -> (\"阿啊呵腌|嗄吖锕||錒\" \"爱 ... 溾\" \"厂广安 ... 菴馣\" \"昂盎 ... 軮䇦\" \"奥澳 ... 鴢泑\")") (defvar pyim-pymap--cchar2py-cache nil "汉字转拼音功能需要的变量. 类似: \"艾\" -> (\"yi\" \"ai\")") (defvar pyim-pymap--py2duoyinzi-cache1 nil "汉字转拼音功能需要的变量") (defvar pyim-pymap--py2duoyinzi-cache2 nil "汉字转拼音功能需要的变量") ;; ** "汉字 -> 拼音" 以及 "拼音 -> 汉字" 的转换函数 (defun pyim-pymap-cache-create (&optional force) "创建 pymap 相关的 cache." (pyim-pymap--cchar2py-cache-create force) (pyim-pymap--py2cchar-cache-create force) (pyim-pymap--py2duoyinzi-cache-create force)) (defun pyim-pymap--cchar2py-cache-create (&optional force) "Build pinyin cchar->pinyin hashtable from `pyim-pymap'. If FORCE is non-nil, FORCE build." (when (or force (not pyim-pymap--cchar2py-cache)) (setq pyim-pymap--cchar2py-cache (make-hash-table :size 50000 :test #'equal)) (dolist (x pyim-pymap) (let ((py (car x)) (cchar-list (string-to-list (car (cdr x))))) ;; NOTE: "|" 是做为分割符使用的,删除。 (dolist (cchar (remove ?| cchar-list)) (let* ((key (char-to-string cchar)) (cache (gethash key pyim-pymap--cchar2py-cache))) (if cache (puthash key (append (list py) cache) pyim-pymap--cchar2py-cache) (puthash key (list py) pyim-pymap--cchar2py-cache)))))))) (defun pyim-pymap--py2cchar-cache-create (&optional force) "构建 pinyin 到 chinese char 的缓存. 用于加快搜索速度,这个函数将缓存保存到 `pyim-pymap-py2cchar-cache' 变量中, 如果 FORCE 设置为 t, 强制更新索引。" (when (or force (not pyim-pymap--py2cchar-cache1) (not pyim-pymap--py2cchar-cache2) ;; FIXME: 我偶尔会遇到一个奇怪的问题,创建的缓存没有包含所有的汉字拼 ;; 音,原因未知,所以这里测试一下,看排在最后面的一个汉字拼音是否包 ;; 含在缓存中,如果不包含,就重新创建缓存。 (and pyim-pymap--py2cchar-cache1 (not (gethash "zuo" pyim-pymap--py2cchar-cache1)))) (setq pyim-pymap--py2cchar-cache1 (make-hash-table :size 50000 :test #'equal)) (setq pyim-pymap--py2cchar-cache2 (make-hash-table :size 50000 :test #'equal)) (setq pyim-pymap--py2cchar-cache3 (make-hash-table :size 50000 :test #'equal)) (dolist (x pyim-pymap) (let* ((py (car x)) (cchars (cdr x)) (n (min (length py) 7))) (puthash py cchars pyim-pymap--py2cchar-cache1) (puthash py (cdr (split-string (car cchars) "")) pyim-pymap--py2cchar-cache2) (dotimes (i n) (let* ((key (substring py 0 (+ i 1))) (orig-value (gethash key pyim-pymap--py2cchar-cache3))) (puthash key (delete-dups `(,@orig-value ,@cchars)) pyim-pymap--py2cchar-cache3))))))) (defun pyim-pymap--py2duoyinzi-cache-create (&optional force) "构建 pinyin 到多音字的缓存,如果 FORCE 设置为 t, 强制更新索引。" (when (or force (not pyim-pymap--py2duoyinzi-cache1) (not pyim-pymap--py2duoyinzi-cache2)) (setq pyim-pymap--py2duoyinzi-cache1 (make-hash-table :size 50000 :test #'equal)) (setq pyim-pymap--py2duoyinzi-cache2 (make-hash-table :size 50000 :test #'equal)) (dolist (x pyim-pymap-duoyinzi-chars) (let* ((py (car x)) (chars (delete-dups `(,@(cdr x) ,@(gethash py pyim-pymap--py2duoyinzi-cache1))))) (puthash py chars pyim-pymap--py2duoyinzi-cache1))) (dolist (x pyim-pymap-duoyinzi-words) (let* ((py (car x)) (words (delete-dups `(,@(cdr x) ,@(gethash py pyim-pymap--py2duoyinzi-cache2))))) (puthash py words pyim-pymap--py2duoyinzi-cache2))))) (defun pyim-pymap-py2cchar-get (pinyin &optional equal-match return-list include-seperator) "获取拼音与 PINYIN 想匹配的所有汉字. 比如: “man” -> (\"忙茫盲芒氓莽蟒邙漭硭\" \"满慢漫曼蛮馒瞒蔓颟谩墁幔螨鞔鳗缦熳镘\") 如果 EQUAL-MATCH 是 non-nil, 获取和 PINYIN 完全匹配的汉字。 如果 RETURN-LIST 是 non-nil, 返回一个由单个汉字字符串组成的列表。 (\"满\" \"慢\" \"漫\" ...) 如果 INCLUDE-SEPERATOR 是 non-nil, 返回的列表包含一个 \"|\" 号,pyim 用这个分隔符 来区分 3500 个常用汉字和生僻字。" (pyim-pymap--py2cchar-cache-create) (when (and pinyin (stringp pinyin)) (let ((output (if equal-match (if return-list (gethash pinyin pyim-pymap--py2cchar-cache2) (gethash pinyin pyim-pymap--py2cchar-cache1)) (gethash pinyin pyim-pymap--py2cchar-cache3)))) (setq output (remove "" output)) (if include-seperator output (remove "|" output))))) (defun pyim-pymap-str2py-get (string) "将 STRING 转换为拼音列表,转换过程中尽可能矫正多音字。 比如: 1. STRING: 你好 2. OUTPUTS: ((\"ni\" \"hao\")) 注意事项: 1. 这个函数遇到非汉字字符串时,原样输出。 2. 多音字矫正依赖 pymap 自带的多音字矫正信息的完善程度,可能会出 现矫正不正确的情况,这个函数为了保证性能,只处理常用多音字。" (let* ((chars (pyim-pymap-split-string string t)) (pinyins-list ;; ("Hello" "银" "行") -> (("Hello") ("yin") ("hang" "xing")) (mapcar (lambda (str) (if (pyim-string-match-p "\\cc" str) (pyim-pymap-cchar2py-get str) (list str))) chars))) ;; 通过排列组合的方式, 重排 pinyins-list。 ;; 比如:(("Hello") ("yin") ("hang")) -> (("Hello" "yin" "hang")) (pyim-permutate-list (pyim-pymap--adjust-duoyinzi chars pinyins-list)))) (defun pyim-pymap-split-string (string &optional to-cchar) "将 STRING 按照中文处理的标准切开. 1. Hello你好 -> (\"Hello\" \"你\" \"好\"), when TO-CCHAR is non-nil. 2. Hello你好 -> (\"Hello\" \"你好\"), when TO-CCHAR is nil." (let* ((chars (split-string string "")) (sep 'pymap-separator) (chars-with-seps (pyim-pymap--add-seps-to-chars chars sep to-cchar)) (chars-grouped (pyim-split-list chars-with-seps sep)) (substrings-list (mapcar #'string-join chars-grouped))) (remove "" substrings-list))) (defun pyim-pymap--add-seps-to-chars (chars separator to-cchar) "在 CCHRS 列表的中英文之间或者中文与中文之间插入 SEPARATOR 元素。 如果 SEPARATOR 设置为 mysep, 那么: 1. TO-CCHAR is nil: (\"a\" \"你\" \"好\" \"b\" \"c\") => (\"a\" mysep \"你\" \"好\" mysep \"b\" \"c\") 2. TO-CCHAR is non-nil: (\"a\" \"你\" \"好\" \"b\" \"c\") => (\"a\" mysep \"你\" mysep \"好\" mysep \"b\" \"c\")" (cl-mapcan (lambda (a b) (let ((a-cchar-p (pyim-pymap-cchar2py-get a)) (b-cchar-p (pyim-pymap-cchar2py-get b))) (cond ;; 如果 to-char 为 non-nil, 中文与中文之间插入一个 ;; sep, 否则不需要插入 sep. ((and a-cchar-p b-cchar-p) (if to-cchar (list a separator) (list a))) ;; 非中文之间不需要插入一个 sep. ((and (not a-cchar-p) (not b-cchar-p)) (list a)) ;; 中文和非中文之间需要插入一个 sep. (t (list a separator))))) chars (cdr chars))) (defun pyim-pymap-cchar2py-get (char-or-str) "获取字符或者字符串 CHAR-OR-STR 对应的拼音 code. pyim 在特定的时候需要读取一个汉字的拼音,这个工作由此完成,函数 从 `pyim-pymap--cchar2py-cache' 查询得到一个汉字字符的拼音, 例如: (pyim-pymap-cchar2py-get ?我) 结果为: (\"wo\")" (pyim-pymap--cchar2py-cache-create) (let ((key (if (characterp char-or-str) (char-to-string char-or-str) char-or-str))) (when (= (length key) 1) (gethash key pyim-pymap--cchar2py-cache)))) (defun pyim-pymap--adjust-duoyinzi (cchars-list pinyins-list) "根据 CCHARS-LIST 对 PINYINS-LIST 进行校正。 比如: 1. CCHARS-LIST: (\"人\" \"民\" \"银\" \"行\") 2. PINYINS-LIST: ((\"ren\") (\"min\") (\"yin\") (\"hang\" \"xing\")) 3. 输出结果为: ((\"ren\") (\"min\") (\"yin\") (\"hang\")) 这个函数依赖 `pyim-pymap-duoyinzi' 提供的多音字数据。" (let ((n (length pinyins-list)) output) (dotimes (i n) (let ((pinyins (nth i pinyins-list)) ;; 当前位置对应的汉字和位置前后汉字组成的两字词语。 (words-list (list (when (>= (- i 1) 0) (concat (nth (- i 1) cchars-list) (nth i cchars-list))) (when (< (+ i 1) n) (concat (nth i cchars-list) (nth (+ i 1) cchars-list))))) ;; 当前位置汉字 (char-list (list (nth i cchars-list)))) (if (= (length pinyins) 1) (push pinyins output) (let ((py-adjusted (or ;; NOTE: 多音字校正规则: ;; 1. 首先通过 pyim 自带的多音字词语来校正,具体见: ;; `pyim-pymap-duoyinzi-words' (pyim-pymap--possible-cchar-pinyin pinyins words-list) ;; 2. 然后通过 pyim 自带的多音字常用读音进行校正, 具体见: ;; `pyim-pymap-duoyinzi-chars', ;; ;; NOTE: 如果用户想要使用某个汉字的偏僻读音,这样处理是有问题 ;; 的,但大多数情况我们还是使用汉字的常用读音,让偏僻的读音进 ;; 入用户个人词库似乎也没有什么好处。 (pyim-pymap--possible-cchar-pinyin pinyins char-list t)))) ;; 3. 如果多音字校正没有结果,就使用未校正的信息。 (push (if py-adjusted (list py-adjusted) pinyins) output))))) (reverse output))) (defun pyim-pymap--possible-cchar-pinyin (cchar-pinyins cchar-words &optional search-char) "寻找一个汉字当前最可能的读音。 以 (行) 作为例子: 1. PINYINS: 此汉字所有的读音组成的列表,比如: (xing hang) 2. WORDS: 此汉字本身或者和前后汉字组成的词语,比如: (银行 行业) 3. SEARCH-CHAR: 如果仅仅搜索汉字本身,就设置为 t, 此处设置为 nil. 4. 返回结果: hang" (cl-find-if (lambda (pinyin) (when-let ((x (string-join (pyim-pymap--py2duoyinzi-get pinyin search-char) "-"))) (cl-some (lambda (word) (and word (string-match-p word x))) cchar-words))) cchar-pinyins)) (defun pyim-pymap--py2duoyinzi-get (pinyin &optional return-chars) "获取与 PINYIN 想匹配的多音字(词)。" (pyim-pymap--py2duoyinzi-cache-create) (when (and pinyin (stringp pinyin)) (if return-chars (gethash pinyin pyim-pymap--py2duoyinzi-cache1) (gethash pinyin pyim-pymap--py2duoyinzi-cache2)))) (defun pyim-pymap-duoyinzi-include-p (cstring) "判断 CSTRING 中文字符串是否包含多音字。" (pyim-pymap--cchar2py-cache-create) (let ((chars (split-string cstring ""))) (cl-some (lambda (char) (> (length (pyim-pymap-cchar2py-get char)) 1)) chars))) ;; * Footer (provide 'pyim-pymap) ;;; pyim-pymap.el ends here pyim-5.3.3/pyim-dregcache.el0000644000175000017500000005173114262115565015553 0ustar dogslegdogsleg;;; pyim-dregcache --- map dictionary to plain cache and use regular expression to search -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2019-2021 Free Software Foundation, Inc. ;; Author: Chen Bin ;; Maintainer: Chen Bin ;; Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;; * 说明文档 :doc: ;; 这个文件将词典直接映射到内存.使用正则表达式(Regular Expression)搜索词库. ;; 搜索速度较快,消耗内存极少. ;; ;; 可以 (setq pyim-dcache-backend 'pyim-dregcache) 然后重启输入法启用此引擎 ;;; Code: ;; * 代码 :code: (require 'pyim-common) (require 'pyim-dict) (require 'subr-x) (require 'pyim-dcache) (defvar pyim-dregcache-cache nil) (defvar pyim-dregcache-loaded-dict-files nil) (defvar pyim-dregcache-icode2word nil) (defvar pyim-dregcache-iword2count nil) (defvar pyim-dregcache-dicts-md5 nil) ;; ** 获取当前可用后端 (cl-defmethod pyim-dcache-backend (&context (pyim-dcache-backend (eql pyim-dregcache))) "返回当前可用的 dcache backend." (if (and (featurep 'pyim-dregcache) ;; pyim-dregcache 后端目前只支持全拼或者双拼。 (pyim-scheme-quanpin-p (pyim-scheme-current))) 'pyim-dregcache 'pyim-dhashcache)) ;; ** 初始化 dregcache 相关函数 (cl-defmethod pyim-dcache-init-variables (&context ((pyim-dcache-backend) (eql pyim-dregcache))) "初始化 cache 缓存相关变量." (pyim-dcache-init-variable pyim-dregcache-iword2count ;; dregcache 引擎也需要词频信息,第一次使用 dregcache 引擎的时候, ;; 自动导入 dhashcache 引擎的词频信息,以后两个引擎的词频信息就 ;; 完全分开了。 (pyim-dcache-get-value 'pyim-dhashcache-iword2count)) (unless pyim-dregcache-icode2word (pyim-dregcache--update-personal-words t))) ;; ** 从 dregcache 搜索词条相关函数 (cl-defmethod pyim-dcache-get (key &context ((pyim-dcache-backend) (eql pyim-dregcache)) &optional from) "从 FROM 中搜索 KEY, 得到对应的结果。 用于 pyim-dregcache 类型的 dcache 后端。" (setq from (or from '(icode2word code2word))) (when key (let (value result) (dolist (x from) (setq value (pyim-dregcache--get-key-from-dcache-type key x)) ;; 处理 iword2count. (unless (listp value) (setq value (list value))) (when value (setq result (append result value)))) result))) (defun pyim-dregcache--get-key-from-dcache-type (key dcache-type) (cond ((memq dcache-type '(icode2word ishortcode2word)) (pyim-dregcache--get-icode2word-ishortcode2word key)) ((memq dcache-type '(code2word shortcode2word)) (pyim-dregcache--get-code2word-shortcode2word key)) ((memq dcache-type '(iword2count)) (gethash key pyim-dregcache-iword2count)) ;; FIXME: pyim-dregcache 暂时不支持 iword2count-recent-10-words 和 ;; iword2count-recent-50-words. ((memq dcache-type '(iword2count-recent-10-words iword2count-recent-50-words)) nil) ;; pyim-dregcache 目前只能用于全拼输入法,而 pyim 中全拼输入法代码反查 ;; 功能是通过 pymap 相关函数实现的,不使用 word2code. ((memq dcache-type '(word2code)) nil) (t nil))) (defun pyim-dregcache--get-code2word-shortcode2word (code) (let ((dict-files (pyim-dregcache-cached-dict-files)) result) (when pyim-debug (message "pyim-dregcache--get-code2word-shortcode2word called. code=%s dict-files=%s" code dict-files)) (when pyim-debug (message "pyim-dregcache--get is called. code=%s" code)) (when dict-files (dolist (file dict-files) ;; please note file is a symbol, not string (let* ((file-info (plist-get pyim-dregcache-cache file)) (content (pyim-dregcache--get-content code file-info))) (setq result (append (pyim-dregcache--get-1 content code) result))))) ;; `push' plus `nreverse' is more efficient than `add-to-list' ;; Many examples exist in Emacs' own code (nreverse result))) (defun pyim-dregcache--get-icode2word-ishortcode2word (code) "以 CODE 搜索个人词和个人联想词. 正则表达式搜索词库,不需要为联想词开单独缓存." (when pyim-debug (message "pyim-dregcache--get-icode2word-ishortcode2word called => %s" code)) (when pyim-dregcache-icode2word (nreverse (pyim-dregcache--get-1 pyim-dregcache-icode2word code)))) (defmacro pyim-dregcache--match-line (code) `(concat "^" (pyim-dregcache--code2regexp ,code) " \\(.+\\)")) (defun pyim-dregcache--get-1 (content code) (let ((case-fold-search t) (start 0) (pattern (pyim-dregcache--match-line code)) (content-length (length content)) word output) (while (and (< start content-length) (setq start (string-match pattern content start))) ;; 提取词 (setq word (match-string-no-properties 1 content)) (when word (cond ((string-match "^[^ ]+$" word) ;; 单个词 (push word output)) (t ;; 多个字 (setq output (append (nreverse (split-string word " +")) output))))) ;; 继续搜索 (setq start (+ start 2 (length code) (length word)))) output)) (defmacro pyim-dregcache--is-shenmu (code) "判断CODE 是否是一个声母." `(and (eq (length ,code) 1) (not (string-match ,code "aeo")))) (defmacro pyim-dregcache--shenmu2regexp (char) "将声母 CHAR 转换为通用正则表达式匹配所有以该声母开头的汉字." `(concat ,char "[a-z]*")) (defun pyim-dregcache--code2regexp (code) "将 CODE 转换成正则表达式用来搜索辞典缓存中的匹配项目. 单个声母会匹配所有以此生母开头的单个汉字." (let* (arr) (cond ((pyim-dregcache--is-shenmu code) ;; 用户输入单个声母如 "w", "y", 将该声母转换为 ;; 通用正则表达式匹配所有以该声母开头的汉字 (pyim-dregcache--shenmu2regexp code)) ((eq (length (setq arr (split-string code "-"))) 1) ;; 用户输入单个汉字的声母和韵母如 "wan", "dan", 不做任何处理 code) (t ;; 用户输入多字词的code,如果某个字只提供了首个声母,将该声母转换为 ;; 通用正则表达式匹配所有以该声母开头的汉字 (let* ((s (mapconcat (lambda (e) (if (pyim-dregcache--is-shenmu e) (pyim-dregcache--shenmu2regexp e) e)) arr "-"))) ;; 当输入3字拼音时,也搜索前3字包含此拼音的更长的词. ;; 三字词很少(可 grep -rEsoh "^[a-z]+(-[a-z]+){2}( [^ ]+){2,6}" 验证) ;; 用户通常输入4字或更多字的词. ;; 例如符合 bei-jin-tian 的词很少, "北京天安门"是更可能匹配的词 ;; `pyim-dregcache' 搜索算法可以保证更长的词在靠后的位置 (cond ((< (length arr) 3) s) ((eq ?* (elt s (1- (length s)))) ;; 简化正则表达式, tian-an-m[a-z]* => tian-an-m[a-z]?[a-z-]* (concat (substring s 0 (1- (length s))) "?[a-z-]*")) (t ;; tian-an-men => tian-an-men[a-z-]* (concat s "[a-z-]*")))))))) (defun pyim-dregcache-cached-dict-files () "所有词典文件." pyim-dregcache-loaded-dict-files) (defun pyim-dregcache--get-content (code file-info) "找到 CODE 对应的字典子缓冲区. FILE-INFO 是字典文件的所有信息." (let* ((rlt (plist-get file-info :content)) idx (ch (elt code 0))) (cond ((< ch ?i) (setq idx (- ch ?a))) ((< ch ?u) ;; 'i' could not be first character of pinyin code (setq idx (- ch ?a 1))) (t ;; 'i', 'u', 'v' could not be first character of pinyin code (setq idx (- ch ?a 3)))) ;; fetch segment using the first character of pinyin code (nth idx rlt))) ;; ** 给 dregcache 添加词条相关函数 (cl-defmethod pyim-dcache-insert-word (word code prepend &context ((pyim-dcache-backend) (eql pyim-dregcache))) "将词条 WORD 插入到 `pyim-dregcache-icode2word'." (pyim-dregcache--insert-word-into-icode2word word code prepend)) (defun pyim-dregcache--insert-word-into-icode2word (word code prepend) "保存个人词到缓存,和其他词库格式一样以共享正则搜索算法." (when pyim-debug (message "pyim-dregcache--insert-word-into-icode2word called => %s %s %s" word code prepend)) (with-temp-buffer (when pyim-dregcache-icode2word (insert pyim-dregcache-icode2word)) (goto-char (point-min)) (let* ((case-fold-search t) substring replace-string beg end old-word-list) (if (re-search-forward (concat "^" code " \\(.*\\)") nil t) (progn (setq beg (match-beginning 0)) (setq end (match-end 0)) (setq substring (match-string-no-properties 1)) (delete-region beg end) ;; 这里不进行排序,在pyim-dregcache--update-personal-words排序 (setq old-word-list (pyim-dregcache--sort-words (split-string substring " "))) (setq replace-string (concat code " " (string-join (delete-dups `(,@old-word-list ,word)) " ")))) (setq replace-string (concat code " " (or replace-string word) "\n"))) (goto-char (or beg (point-max))) (insert replace-string)) (setq pyim-dregcache-icode2word (buffer-string)))) ;; ** 从 dregcache 删除词条相关函数 (cl-defmethod pyim-dcache-delete-word (word &context ((pyim-dcache-backend) (eql pyim-dregcache))) "将中文词条 WORD 从个人词库中删除." (with-temp-buffer (insert pyim-dregcache-icode2word) (goto-char (point-min)) (let* ((case-fold-search t) substring beg end) (while (re-search-forward (concat "^\\([a-z-]+\\) \\(.*\\)" word "\\(.*\\)$") nil t) (setq beg (match-beginning 0)) (setq end (match-end 0)) (setq substring (concat (match-string-no-properties 1) (match-string-no-properties 2) (match-string-no-properties 3))) ;; delete string and the newline char (delete-region beg (+ 1 end)) (when (> (length (split-string substring " ")) 1) (goto-char beg) (insert substring))) (setq pyim-dregcache-icode2word (buffer-string)))) ;; 删除对应词条的词频 (remhash word pyim-dregcache-iword2count)) ;; ** 更新 dregcache 相关函数 (cl-defmethod pyim-dcache-update (&context ((pyim-dcache-backend) (eql pyim-dregcache)) &optional force) "读取并加载所有相关词库 dcache. 如果 FORCE 为真,强制加载。" (pyim-dregcache--update-personal-words force) (let* ((dict-files (pyim-dict-get-enabled-dict-files)) (dicts-md5 (pyim-dcache-create-files-md5 dict-files))) (when pyim-debug (message "pyim-dregcache--update: pyim-dicts=%s pyim-extra-dicts=%s dict-files=%s" pyim-dicts pyim-extra-dicts dict-files)) (pyim-dregcache--update-code2word dict-files dicts-md5 force))) (defun pyim-dregcache--update-personal-words (&optional force) "合并 `pyim-dregcache-icode2word' 磁盘文件. 加载排序后的结果. 在这个过程中使用了 `pyim-dregcache-iword2count' 中记录的词频信息。 如果 FORCE 为真,强制排序" (let* ((content (pyim-dregcache--load-variable 'pyim-dregcache-icode2word))) (when content (with-temp-buffer (let* (prev-record prev-code record code prev-point) (when pyim-dregcache-icode2word (insert pyim-dregcache-icode2word)) (insert content) (sort-lines nil (point-min) (point-max)) (delete-duplicate-lines (point-min) (point-max) nil t nil) (goto-char (point-min)) (unless (re-search-forward "utf-8-unix" (line-end-position) t) (insert "## -*- coding: utf-8-unix -*-\n")) (goto-char (point-min)) (while (not (eobp)) ;; initiate prev-point and prev-line (goto-char (line-beginning-position)) (setq prev-point (point)) (setq prev-record (pyim-dline-parse)) (setq prev-code (car prev-record)) ;; 词库在创建时已经保证1个code只有1行,因此合并词库文件一般只有2行需要合并 ;; 所以这里没有对2行以上的合并进行优化 (when (= (forward-line 1) 0) (setq record (pyim-dline-parse)) (setq code (car record)) (when (string-equal prev-code code) ;; line-end-position donesn't contain "\n" (progn (delete-region prev-point (line-end-position)) (insert (string-join (delete-dups `(,@prev-record ,@record)) " "))))))) (setq pyim-dregcache-icode2word (buffer-string))))) (when (and force pyim-dregcache-icode2word) (pyim-dregcache--sort-icode2word))) (defun pyim-dregcache--load-variable (variable) "载入 VARIABLE 对应的文件内容." (let* ((file (pyim-dregcache--variable-file variable))) (when (and file (file-exists-p file)) (with-temp-buffer (insert-file-contents file) (buffer-string))))) (defun pyim-dregcache--variable-file (variable) "Get VARIABLE dcache file path." (concat (file-name-as-directory pyim-dcache-directory) (symbol-name variable))) (defun pyim-dregcache--update-code2word (dict-files dicts-md5 &optional force) "读取并加载词库. 读取词库文件 DICT-FILES,生成对应的词库缓冲文件,然后加载词库缓存。 DICT-FILES 是词库文件列表. DICTS-MD5 是词库的MD5校验码. 如果 FORCE 为真,强制加载。" (interactive) (when (or force (not (equal dicts-md5 pyim-dregcache-dicts-md5))) ;; no hashtable i file mapping algorithm (dolist (file dict-files) (pyim-dregcache--load-dictionary-file file)) (setq pyim-dregcache-dicts-md5 dicts-md5))) (defun pyim-dregcache-reset-cache () "Reset dregcache backend's cache." (setq pyim-dregcache-cache nil) (setq pyim-dregcache-loaded-dict-files nil)) (defun pyim-dregcache--load-dictionary-file (dict-file) "READ from DICT-FILE." (let* ((raw-content (with-temp-buffer (insert-file-contents dict-file) (buffer-string))) (file (intern (file-truename dict-file)))) (unless (memq file pyim-dregcache-loaded-dict-files) (push file pyim-dregcache-loaded-dict-files)) (setq pyim-dregcache-cache (plist-put pyim-dregcache-cache file (pyim-dregcache--create-cache-content raw-content))))) (defun pyim-dregcache--create-cache-content (raw-content) "将 RAW-CONTENT 划分成可以更高效搜索的缓冲区." (let ((chars "bcdefghjklmnopqrstwxyz") (i 0) content-segments (start (string-match "^a" raw-content)) chunk end) ;; 将字典缓存划分成多个"子搜索区域" (while (< i (length chars)) (when (setq end (string-match (string ?^ (elt chars i)) raw-content start)) (setq chunk (substring-no-properties raw-content start end)) (push chunk content-segments) (setq start end)) (setq i (1+ i))) ;; last chunk (setq chunk (substring-no-properties raw-content end (length raw-content))) (push chunk content-segments) (list :content (nreverse content-segments)))) ;; ** 更新 dregcache 词频功能。 (cl-defmethod pyim-dcache-update-wordcount (word &context ((pyim-dcache-backend) (eql pyim-dregcache)) &optional wordcount-handler) (pyim-dregcache--update-iword2count word wordcount-handler)) (defun pyim-dregcache--update-iword2count (word &optional wordcount-handler) "保存词频到缓存." (when pyim-debug (message "pyim-dregcache--update-iword2count. word=%s" word)) (let* ((orig-value (or (gethash word pyim-dregcache-iword2count) 0)) (new-value (cond ((functionp wordcount-handler) (funcall wordcount-handler orig-value)) ((numberp wordcount-handler) wordcount-handler) (t (+ orig-value 1))))) (unless (equal orig-value new-value) (puthash word new-value pyim-dregcache-iword2count)))) ;; ** 升级 dregcache 相关函数 (cl-defmethod pyim-dcache-upgrade (&context ((pyim-dcache-backend) (eql pyim-dregcache))) "升级词库缓存. 当前已有的功能: 1. 基于 :code-prefix-history 信息,升级为新的 code-prefix。" (pyim-dregcache--upgrade-icode2word)) (defun pyim-dregcache--upgrade-icode2word () "升级 icode2word 缓存。 dregcache 只支持全拼和双拼,不能用于五笔之类的型码输入法,而 update-icode2word 目前只要是用于更新型码输入法的 code-prefix, 所 以不需要具体实现细节。") ;; ** 根据 dregcache 信息对词条进行排序 (defun pyim-dregcache--sort-words (words-list) "对 WORDS-LIST 排序,词频大的排在前面." (let ((iword2count pyim-dregcache-iword2count)) (sort words-list (lambda (a b) (let ((a (car (split-string a ":"))) (b (car (split-string b ":")))) (> (or (gethash a iword2count) 0) (or (gethash b iword2count) 0))))))) ;; ** 保存 dregcache 相关函数 (cl-defmethod pyim-dcache-save-caches (&context ((pyim-dcache-backend) (eql pyim-dregcache))) (pyim-dregcache--save-personal-dcache-to-file)) (defun pyim-dregcache--save-personal-dcache-to-file () "保存缓存内容到默认目录." (when pyim-debug (message "pyim-dregcache--save-personal-dcache-to-file called")) ;; 用户选择过的词存为标准辞典格式保存 (when pyim-dregcache-icode2word (pyim-dregcache--save-variable 'pyim-dregcache-icode2word pyim-dregcache-icode2word)) ;; 词频 (pyim-dcache-save-variable 'pyim-dregcache-iword2count pyim-dregcache-iword2count)) (defun pyim-dregcache--save-variable (variable value) "Save VARIABLE with its VALUE." (let* ((file (pyim-dregcache--variable-file variable)) (save-silently t)) (make-directory (file-name-directory file) t) (with-temp-buffer (insert value) (pyim-dcache-write-file file)))) ;; ** 导出 dregcache 相关函数 (cl-defmethod pyim-dcache-export-words-and-counts (_file &context ((pyim-dcache-backend) (eql pyim-dregcache)) &optional _confirm) "TODO") (cl-defmethod pyim-dcache-export-personal-words (file &context ((pyim-dcache-backend) (eql pyim-dregcache)) &optional confirm) "将个人词库存入 FILE." (when pyim-dregcache-icode2word ;; 按词频排序,把词频信息保存到用户词典 (pyim-dregcache--sort-icode2word) (with-temp-buffer (insert pyim-dregcache-icode2word) ;; 删除单字词 (goto-char (point-min)) (while (re-search-forward "^[a-z]+ [^a-z]*" nil t) (replace-match "" nil t)) ;; 按拼音排序 (sort-lines nil (point-min) (point-max)) (pyim-dcache-write-file file confirm)))) (defun pyim-dregcache--sort-icode2word () "对个人词库排序." ;; https://github.com/redguardtoo/zhfreq (with-temp-buffer (dolist (l (split-string pyim-dregcache-icode2word "\n")) (cond ((string-match "^\\([a-z-]+ \\)\\(.*\\)" l) ;; 3字以上词很少,如果只处理单字,2字词,3字词 ;; ((string-match "^\\([a-z]+ \\|[a-z]+-[a-z]+ \\|[a-z]+-[a-z]+-[a-z]+ \\)\\(.*\\)" l) (let* ((pinyin (match-string 1 l)) (words (pyim-dregcache--sort-words (split-string (match-string 2 l) " ")))) (insert (format "%s\n" (concat pinyin (string-join words " ")))))) ;; 其他词 ((string= l "") ;; skip empty line ) (t (insert (format "%s\n" l))))) (setq pyim-dregcache-icode2word (buffer-string)))) ;; * Footer (provide 'pyim-dregcache) ;;; pyim-dregcache.el ends here pyim-5.3.3/pyim-pkg.el0000644000175000017500000000077014476561516014434 0ustar dogslegdogsleg;; Generated package description from pyim.el -*- no-byte-compile: t -*- (define-package "pyim" "5.3.3" "A Chinese input method support quanpin, shuangpin, wubi, cangjie and rime." '((emacs "27.1") (async "1.6") (xr "1.13")) :commit "64067b20ce0e964b1342b378180f24a1d4503797" :authors '(("Ye Wenbin" . "wenbinye@163.com") ("Feng Shu" . "tumashu@163.com")) :maintainer '("Feng Shu" . "tumashu@163.com") :keywords '("convenience" "chinese" "pinyin" "input-method") :url "https://github.com/tumashu/pyim") pyim-5.3.3/pyim-outcome.el0000644000175000017500000002134114412763713015314 0ustar dogslegdogsleg;;; pyim-outcome.el --- outcome handle tools for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-common) (require 'pyim-scheme) (defgroup pyim-outcome nil "Outcome tools for pyim." :group 'pyim) (defvaralias 'pyim-magic-converter 'pyim-outcome-magic-converter) (defcustom pyim-outcome-magic-converter nil "将 “待选词条” 在 “上屏” 之前自动转换为其他字符串. 这个功能可以实现“简转繁”,“输入中文得到英文”之类的功能。" :type '(choice (const nil) function)) (defcustom pyim-outcome-trigger "v" "用于触发特殊操作的字符,相当与单字快捷键. 输入中文的时候,我们需要快速频繁的执行一些特定的命令,最直接的方 法就是将上述命令绑定到一个容易按的快捷键上,但遗憾的是 emacs 大多 数容易按的快捷键都 *名花有主* 了,甚至找一个 “Ctrl+单字符”的快 捷键都不太容易,特殊功能触发字符,可以帮助我们实现“单字符”快捷 键,类似 org-mode 的 speed key。 默认情况下,我们可以使用特殊功能触发字符执行下面几个操作(假设触 发字符为 v): 1. 快速切换中英文标点符号的样式:当光标前的字符是一个标点符号时, 按 \"v\" 可以切换这个标点的样式。比如:光标在A处的时候,按 \"v\" 可以将A前面的全角逗号转换为半角逗号。 你好,-A- 按 \"v\" 后 你好,-A- 2. 快速将光标前的词条添加到词库:当光标前的字符是中文字符时,按 \"num\" + \"v\" 可以将光标前 num 个中文汉字组成的词条添加到个 人词频文件中,比如:当光标在A处时,按\"4v\"可以将“的红烧肉” 这个词条加入个人词频文件,默认num不超过9。 我爱吃美味的红烧肉-A- 值得注意的是,这种方式如果添加的功能太多,会造成许多潜在的冲突。 用户可以使用变量 `pyim-outcome-trigger' 来设置触发字符,默 认的触发字符是:\"v\", 选择这个字符的理由基于全拼输入法的: 1. \"v\" 不是有效的声母,不会对中文输入造成太大的影响。 2. \"v\" 字符很容易按。 pyim 使用函数 `pyim-process-select-handle-char' 来处理特殊功能触发字符。当待输入的 字符是触发字符时,`pyim-process-select-handle-char' 根据光标前的字符的不同来调用不 同的功能,具体见 `pyim-process-select-handle-char' : 单字快捷键受到输入法方案的限制,比如:全拼输入法可以将其设置为v, 但双拼输入法下设置 v 可能就不行,所以,pyim 首先会检查当前输入法 方案下,这个快捷键设置是否合理有效,如果不是一个合理的设置,则使 用拼音方案默认的 :prefer-triggers 。 具体请参考 `pyim-outcome--get-trigger' 。" :type '(choice (const nil) string)) (defcustom pyim-outcome-trigger-function #'pyim-outcome-trigger-function-default "可以使用 `pyim-outcome-trigger' 激活的函数。 这个函数与『单字快捷键配合使用』,当光标前面的字符为汉字字符时, 按 `pyim-outcome-trigger' 对应字符,可以调用这个函数来处理 光标前面的文字内容。" :type 'function) (defvar pyim-outcome--history nil "记录 pyim outcome 的变化的历史 在 pyim 中 outcome 代表用户通过输入法选择,并最终插入到 buffer 的字符串。 “一次确认就生成的词条” , 当前变量一般只有一个元素,比如: 1. 输入: nihao 2. 输出: 你好 2. 变量取值为: (\"你好\") “多次确认才能生成词条” , 当前变量记录了选择的历史,比如: 1. 输入: yiersansi 2. 输出: 一二三四 3. 第一次选择:一二 4. 第二次选择:三 5. 第三次选择:四 6. 变量取值为: (\"一二三四\" \"一二三\" \"一二\")") (defvar pyim-outcome--magic-convert-cache nil "用来临时保存 `pyim-outcome-magic-convert' 的结果. 从而加快同一个字符串第二次的转换速度。") (pyim-register-local-variables '(pyim-outcome--history)) ;; ** 选词框相关函数 (defun pyim-outcome-get () "获取 outcome" (pyim-outcome--get 0)) (defun pyim-outcome--get (n) "获取 outcome" (nth n pyim-outcome--history)) (defun pyim-outcome-add (outcome) "添加 OUTCOME." (push outcome pyim-outcome--history)) (defun pyim-outcome-diff () "OUTCOME 的变化。" (string-remove-prefix (or (pyim-outcome--get 1) "") (pyim-outcome--get 0))) (defun pyim-outcome-erase () "清除 OUTCOME." (setq pyim-outcome--history nil)) (defun pyim-outcome-magic-convert (str) "用于处理 `pyim-outcome-magic-converter' 的函数。" (if (functionp pyim-outcome-magic-converter) (or (cdr (assoc str pyim-outcome--magic-convert-cache)) (let ((result (funcall pyim-outcome-magic-converter str))) (setq pyim-outcome--magic-convert-cache `((,str . ,result))) result)) str)) (defun pyim-outcome-trigger-p (str) "判断 STR 是否是一个 trigger." (equal (pyim-outcome--get-trigger) str)) (defun pyim-outcome--get-trigger () "检查 `pyim-outcome-trigger' 是否为一个合理的 trigger char 。 pyim 的 translate-trigger-char 要占用一个键位,为了防止用户 自定义设置与输入法冲突,这里需要检查一下这个键位设置的是否合理, 如果不合理,就返回输入法默认设定。" (let* ((user-trigger pyim-outcome-trigger) (user-trigger (if (characterp user-trigger) (char-to-string user-trigger) (when (= (length user-trigger) 1) user-trigger))) (first-char (pyim-scheme-first-chars (pyim-scheme-current))) (prefer-triggers (pyim-scheme-prefer-triggers (pyim-scheme-current)))) (if (and (> (length user-trigger) 0) (pyim-string-match-p (regexp-quote user-trigger) first-char)) (car prefer-triggers) user-trigger))) (defun pyim-outcome-call-trigger-function () (when (functionp pyim-outcome-trigger-function) (funcall pyim-outcome-trigger-function) (message "PYIM: 运行 `pyim-outcome-trigger-function' 函数。"))) (defun pyim-outcome-trigger-function-default (&optional no-space) "默认的 `pyim-outcome-trigger-function'. 这个函数可以清理当前行的内容,比如:删除不必要的空格,等。" (interactive) (let* ((begin (line-beginning-position)) (end (point)) (string (buffer-substring-no-properties begin end)) (sep (if no-space "" " ")) new-string) (when (> (length string) 0) (delete-region begin end) (with-temp-buffer (insert string) (dolist (x `(;; 中文标点与英文之间的空格 ("\\([,。;?!;、)】]\\) *\\([[:ascii:]]\\)" . "") ;; 英文与中文标点之间的空格 ("\\([[:ascii:]]\\) *\\([(【]\\)" . "") ;; 英文与汉字之间的空格 ("\\([a-zA-Z]\\) *\\(\\cc\\)" . ,sep) ;; 汉字与英文之间的空格 ("\\(\\cc\\) *\\([a-zA-Z]\\)" . ,sep) ;; 汉字与汉字之间的空格 ("\\(\\cc\\) +\\(\\cc\\)" . ""))) (dotimes (_ 3) ;NOTE. 数字3是一个经验数字。 (goto-char (point-min)) (while (re-search-forward (car x) nil t) (replace-match (concat (match-string 1) (cdr x) (match-string 2)) nil t)))) (setq new-string (buffer-string))) (insert new-string)))) ;; * Footer (provide 'pyim-outcome) ;;; pyim-outcome.el ends here pyim-5.3.3/pyim-indicator.el0000644000175000017500000001555414412763713015626 0ustar dogslegdogsleg;;; pyim-indicator.el --- pyim indicator for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-common) (require 'pyim-process) (defgroup pyim-indicator nil "Indicator for pyim." :group 'pyim) (defcustom pyim-indicator-list '(pyim-indicator-with-cursor-color pyim-indicator-with-modeline) "PYIM 当前使用的 indicators. Indicator 用于显示输入法当前输入状态(英文还是中文)。" :type '(repeat :tag "Indicator functions" function)) (defcustom pyim-indicator-use-post-command-hook t "pyim-indicator daemon 是否使用 `post-command-hook' 实现。 如果设置为 t, 则使用 `post-command-hook' 实现, 设置为 nil, 则使用 timer 实现。" :type 'boolean) (defvar pyim-indicator-cursor-color (list "orange") "`pyim-indicator-default' 使用的 cursor 颜色。 这个变量的取值是一个list: (中文输入时的颜色 英文输入时的颜色), 如 果英文输入时的颜色为 nil, 则使用默认 cursor 颜色。") (defvar pyim-indicator-modeline-string (list "PYIM/C " "PYIM/E ") "`pyim-indicator-default' 使用的 modeline 字符串。 这个变量的取值是一个list: (中文输入时显示的字符串 英文输入时显示的字符串)。") (defvar pyim-indicator--original-cursor-color nil "记录 cursor 的原始颜色。") (defvar pyim-indicator--timer nil "`pyim-indicator-daemon' 使用的 timer.") (defvar pyim-indicator--timer-repeat 0.4) (defvar pyim-indicator--daemon-function-argument nil "实现 `pyim-indicator--daemon-function' 时,用于传递参数,主要原因 是由于 `post-command-hook' 不支持参数。") (defvar pyim-indicator--last-input-method-title nil "记录上一次 `current-input-method-title' 的取值。") (defun pyim-indicator--start-daemon () "Indicator daemon, 用于实时显示输入法当前输入状态。" (unless pyim-indicator--original-cursor-color (setq pyim-indicator--original-cursor-color (frame-parameter nil 'cursor-color))) (setq pyim-indicator--daemon-function-argument #'pyim-process-indicator-function) (if pyim-indicator-use-post-command-hook (add-hook 'post-command-hook #'pyim-indicator--daemon-function) (unless (timerp pyim-indicator--timer) (setq pyim-indicator--timer (run-with-timer nil pyim-indicator--timer-repeat #'pyim-indicator--daemon-function))))) (add-hook 'pyim-process-start-daemon-hook #'pyim-indicator--start-daemon) (defun pyim-indicator--daemon-function () "`pyim-indicator-daemon' 内部使用的函数。" (while-no-input (redisplay) (ignore-errors (let ((chinese-input-p (and (functionp pyim-indicator--daemon-function-argument) (funcall pyim-indicator--daemon-function-argument)))) (dolist (indicator pyim-indicator-list) (when (functionp indicator) (funcall indicator current-input-method chinese-input-p))))))) (defun pyim-indicator--stop-daemon () "Stop indicator daemon." (interactive) ;; 只有其它的 buffer 中没有启动 pyim 时,才停止 daemon. ;; 因为 daemon 是服务所有 buffer 的。 (unless (cl-find-if (lambda (buf) (buffer-local-value 'current-input-method buf)) (remove (current-buffer) (buffer-list))) (setq pyim-indicator--daemon-function-argument nil) (remove-hook 'post-command-hook #'pyim-indicator--daemon-function) (when (timerp pyim-indicator--timer) (cancel-timer pyim-indicator--timer) (setq pyim-indicator--timer nil)) (pyim-indicator--revert-cursor-color))) (add-hook 'pyim-process-stop-daemon-hook #'pyim-indicator--stop-daemon) (defun pyim-indicator--revert-cursor-color () "将 cursor 颜色重置到 pyim 启动之前的状态。" (when pyim-indicator--original-cursor-color (set-cursor-color pyim-indicator--original-cursor-color))) (defun pyim-indicator-with-cursor-color (input-method chinese-input-p) "Pyim 自带的 indicator, 通过光标颜色来显示输入状态。" (if (not (equal input-method "pyim")) ;; 大多数情况是因为用户切换 buffer, 新 buffer 中 ;; pyim 没有启动,重置 cursor 颜色。 (set-cursor-color pyim-indicator--original-cursor-color) (if chinese-input-p (set-cursor-color (nth 0 pyim-indicator-cursor-color)) (set-cursor-color (or (nth 1 pyim-indicator-cursor-color) (pyim-indicator--select-color (list "black" "white") pyim-indicator--original-cursor-color)))))) (defun pyim-indicator--select-color (colors &optional prefer-color) "根据背景,选择一个比较显眼的颜色。 如果 PREFER-COLOR 和背景颜色差异比较大,就使用 PREFER-COLOR. 否则从 COLORS 中选择一个。" (let ((background (frame-parameter nil 'background-color))) (if (and prefer-color (> (color-distance prefer-color background) (/ (color-distance "black" "white") 2))) prefer-color (car (sort colors (lambda (a b) (> (color-distance a background) (color-distance b background)))))))) (defun pyim-indicator-with-modeline (input-method chinese-input-p) "Pyim 自带的 indicator, 使用 mode-line 来显示输入状态。" (when (equal input-method "pyim") (if chinese-input-p (setq current-input-method-title (nth 0 pyim-indicator-modeline-string)) (setq current-input-method-title (nth 1 pyim-indicator-modeline-string)))) (pyim-indicator--update-mode-line)) (defun pyim-indicator--update-mode-line () "更新 mode-line." (unless (eq pyim-indicator--last-input-method-title current-input-method-title) (force-mode-line-update) (setq pyim-indicator--last-input-method-title current-input-method-title))) ;; * Footer (provide 'pyim-indicator) ;;; pyim-indicator.el ends here pyim-5.3.3/pyim-preview.el0000644000175000017500000001174214256541722015326 0ustar dogslegdogsleg;;; pyim-preview.el --- pinyin tools for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-common) (require 'pyim-process) (require 'mule) (defgroup pyim-preview nil "Preview libs for pyim." :group 'pyim) (defface pyim-preview-face '((t (:underline t))) "设置光标处预览字符串的 face.") (defvar pyim-preview--overlay nil "用于保存光标处预览字符串的 overlay.") (defvar input-method-highlight-flag) ;; fixed compiling error (pyim-register-local-variables '(pyim-preview--overlay)) ;; ** 待输入字符串预览 (defun pyim-preview--setup-overlay () "设置 pyim 光标处实时预览功能所需要的 overlay. 这个函数会在 `pyim-input-method' 中调用,用于创建 overlay ,并将 其保存到 `pyim-preview--overlay' 变量,overlay 的 face 属性设置为 `pyim-preview-face' ,用户可以使用这个变量来自定义 face" (let ((pos (point))) (if (overlayp pyim-preview--overlay) (move-overlay pyim-preview--overlay pos pos) (setq pyim-preview--overlay (make-overlay pos pos)) (if input-method-highlight-flag (overlay-put pyim-preview--overlay 'face 'pyim-preview-face))))) (add-hook 'pyim-process-ui-init-hook #'pyim-preview--setup-overlay) (defun pyim-preview--delete-overlay () "删除 pyim 光标处实时预览功能所需要的 overlay. 这个函数会在 `pyim-input-method' 中调用,用于删除 `pyim-preview--overlay' 中保存的 overlay。" (if (and (overlayp pyim-preview--overlay) (overlay-start pyim-preview--overlay)) (delete-overlay pyim-preview--overlay))) (defun pyim-preview--refresh (&rest _) "刷新光标处预览. pyim 会使用 Emacs overlay 机制在 *待输入buffer* 光标处高亮显示一 个预览字符串,让用户可以查看将要输入的字符串,这个函数用于更新这 个字符串的内容。" (let* ((scheme (pyim-scheme-current)) (preview (pyim-preview-string scheme))) ;; Delete old preview string. (pyim-preview--delete-string) ;; Insert new preview string. (insert preview) ;; Highlight new preview string. (move-overlay pyim-preview--overlay (overlay-start pyim-preview--overlay) (point)))) (add-hook 'pyim-process-ui-refresh-hook #'pyim-preview--refresh) (cl-defgeneric pyim-preview-string (scheme) "获得 preview 字符串。") (cl-defmethod pyim-preview-string (_scheme) "获得 preview 字符串。" (let* ((candidates (pyim-process-get-candidates)) (pos (min (pyim-process-word-position) (1- (length candidates)))) (preview (concat (pyim-process-get-select-result) (nth pos candidates)))) (pyim-process-magic-convert preview))) (cl-defmethod pyim-preview-string ((_scheme pyim-scheme-quanpin)) "获得 preview 字符串,适用于全拼输入法。" (let* ((candidates (pyim-process-get-candidates)) (pos (min (pyim-process-word-position) (1- (length candidates)))) (preview (concat (pyim-process-get-select-result) (nth pos candidates))) (rest (mapconcat (lambda (py) (concat (nth 0 py) (nth 1 py))) (nthcdr (length preview) (pyim-process-get-first-imobj)) "'"))) (when (string< "" rest) (setq preview (concat preview rest))) (pyim-process-magic-convert preview))) (defun pyim-preview--delete-string () "删除已经插入 buffer 的 preview 预览字符串。" (when (and pyim-preview--overlay (overlay-start pyim-preview--overlay)) (delete-region (overlay-start pyim-preview--overlay) (overlay-end pyim-preview--overlay)))) (add-hook 'pyim-process-ui-hide-hook #'pyim-preview--delete-string) (cl-defmethod pyim-process-ui-position () "使用 Preview 字符串的开始位置作为 UI 的放置位置。" (overlay-start pyim-preview--overlay)) ;; * Footer (provide 'pyim-preview) ;;; pyim-preview.el ends here pyim-5.3.3/.dir-locals.el0000644000175000017500000000027714015673356015003 0ustar dogslegdogsleg((nil . ((fill-column . 80) (indent-tabs-mode . nil) (tab-width . 4) (buffer-file-coding-system . utf-8-unix)))) ;; Local Variables: ;; no-byte-compile: t ;; End: pyim-5.3.3/pyim-entered.el0000644000175000017500000000655214256541722015276 0ustar dogslegdogsleg;;; pyim-entered.el --- page lib for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-common) (defgroup pyim-entered nil "Entered tools for pyim." :group 'pyim) (defvar pyim-entered--buffer " *pyim-entered-buffer*" "一个 buffer,用来处理用户已经输入的字符串: entered。 用户 *已经* 输入的字符组成的字符串,在 pyim 里面,叫做 entered, 说白了就是 input, 选择 entered 而不选择 input 的原因是: 1. input 太常见了, 和其它词语组和起来容易产生歧义,比如: pyim-entered-output 就比 pyim-input-output 更加容易理解。 2. entered 这个词语很少见,只要明白它代表的概念,就不容易产生混乱。 pyim 使用一个 buffer 来处理 entered, 以实现 “用户输入字符串” 编 辑等高级功能: 1. 如果输入的字符串有错误,可以修改,不用取消重新输入; 2. 如果光标不在行首,pyim 只使用光标前的字符串来查找词条, 如果词条上屏,词条对应的输入就从 buffer 中清除,然后 继续处理后面的输入,这种方式方便长词的输入; 3. 如果光标在行首,则处理整行。") (defmacro pyim-entered-with-entered-buffer (&rest forms) (declare (indent 0) (debug t)) `(with-current-buffer (get-buffer-create pyim-entered--buffer) ,@forms)) (defun pyim-entered-get (&optional type) "从 `pyim-entered--buffer' 中获取拼音字符串. 默认返回 entered buffer 中的全部字符串。如果 TYPE 取值为 point-before, 返回 entered buffer 中 point 之前的字符串,如果 TYPE 取值为 point-after, 返回 entered buffer 中 point 之后的字符 串。" (pyim-entered-with-entered-buffer (cond ((bobp) (buffer-string)) ((eq type 'point-before) (buffer-substring-no-properties (point-min) (point))) ((eq type 'point-after) (buffer-substring-no-properties (point) (point-max))) (t (buffer-string))))) (defun pyim-entered-erase-buffer () "清除 `pyim-entered--buffer' 的内容" (pyim-entered-with-entered-buffer (erase-buffer))) (defun pyim-entered-in-the-middle-of-entered-p () "判断 entered buffer 中,光标是否在 entered 字符串中间。" (pyim-entered-with-entered-buffer (and (> (point) 1) (< (point) (point-max))))) ;; * Footer (provide 'pyim-entered) ;;; pyim-entered.el ends here pyim-5.3.3/pyim-codes.el0000644000175000017500000000543014246745040014735 0ustar dogslegdogsleg;;; pyim-codes.el --- codes lib for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-scheme) (require 'pyim-imobjs) (require 'pyim-dcache) (cl-defgeneric pyim-codes-create (imobj scheme &optional first-n) "按照 SCHEME 对应的输入法方案,从一个 IMOBJ 创建一个列表 codes. 这个列表包含一个或者多个 code 字符串,这些 code 字符串用于从词库 中搜索词条.") (cl-defmethod pyim-codes-create (imobj (_scheme pyim-scheme-quanpin) &optional first-n) "从IMOBJ 创建一个 code 列表:codes. 列表 codes 中包含一个或者多个 code 字符串,这些 code 字符串用于从 词库中搜索相关词条。 (pyim-codes-create (quote ((\"w\" \"o\" \"w\" \"o\") (\"\" \"ai\" \"\" \"ai\") (\"m\" \"ei\" \"m\" \"ei\") (\"n\" \"v\" \"n\" \"v\"))) (pyim-scheme-get (quote quanpin))) 结果为: (\"wo\" \"ai\" \"mei\" \"nv\")" (mapcar (lambda (w) (let ((py (replace-regexp-in-string ;去掉分隔符,在词库中搜索候选词不需要分隔符 "'" "" (concat (nth 0 w) (nth 1 w))))) (if (numberp first-n) (substring py 0 (min first-n (length py))) py))) imobj)) (cl-defmethod pyim-codes-create (imobj (scheme pyim-scheme-xingma) &optional first-n) "用于处理形码输入法的 `pyim-codes-create' 方法。" (when scheme (let ((code-prefix (pyim-scheme-code-prefix scheme))) (mapcar (lambda (x) (concat (or code-prefix "") (if (numberp first-n) (substring x 0 (min first-n (length x))) x))) imobj)))) ;; * Footer (provide 'pyim-codes) ;;; pyim-imobjs.el ends here pyim-5.3.3/pyim-imobjs.el0000644000175000017500000001327314255423170015124 0ustar dogslegdogsleg;;; pyim-imobjs.el --- imobjs for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-common) (require 'pyim-pinyin) (require 'pyim-scheme) (defgroup pyim-imobjs nil "Imobjs lib for pyim." :group 'pyim) (cl-defgeneric pyim-imobjs-create (entered scheme) "按照 SCHEME 对应的输入法方案,从 ENTERED 字符串中创建一个 或者多个 imobj 组成的列表,不同的输入法,imobj 的结构也是不一样的。") (cl-defmethod pyim-imobjs-create (entered (scheme pyim-scheme-quanpin)) "从用户输入的字符串 ENTERED 创建一个输入法内部对象列表: imobjs. 这个 imobjs 可能包含一个 imobj, 也可能包含多个,每个 imobj 都包含 声母和韵母的相关信息,比如: (pyim-imobjs-create \"woaimeinv\" (pyim-scheme-get \\='quanpin)) 结果为: (((\"w\" \"o\" \"w\" \"o\") (\"\" \"ai\" \"\" \"ai\") (\"m\" \"ei\" \"m\" \"ei\") (\"n\" \"v\" \"n\" \"v\"))) 如果字符串无法正确处理,则特殊处理, 比如: (pyim-imobjs-create \"ua\" (pyim-scheme-get \\='quanpin)) 结果为: (((\"\" \"ua\" \"\" \"ua\"))) 全拼输入法的 imelem 是四个字符串组成的 list, 类似: (\"w\" \"o\" \"w\" \"o\") 代表: (声母1, 韵母1, 声母2, 韵母2) 声母1和韵母1一般用来生成 code 字符串,用于词库中寻找词条。声母2和 韵母2一般用来反向构建 entered 字符串,用于 “多次选择生成词条” 这个 功能。 大多数情况,声母1 = 声母2, 韵母1 = 韵母2, 只有在使用模糊音的时候, 才可能出现不一致的情况。" (when (and entered (string< "" entered)) (let* ((str-list (remove "" (split-string entered "'"))) (n (length str-list)) output) (dotimes (i n) (let* ((str (nth i str-list)) (x (pyim-pinyin-split str))) (if (not x) (setq output nil) (when (> i 0) ;; 将强制分割符号附加到封分割符后面的声母开头, ;; 类似: ("'n" "i" "'n" "i"), 用于 `pyim-page-preview-create' 函数, ;; 和多次选词之后的,用户手动输入的分隔符的保护。 (setf (nth 0 (car x)) (concat "'" (nth 0 (car x)))) (setf (nth 2 (car x)) (concat "'" (nth 2 (car x))))) (setq output (append output x))))) (when output (pyim-imobjs-find-fuzzy (list output) scheme))))) ;; "nihc" -> (((\"n\" \"i\" \"n\" \"i\") (\"h\" \"ao\" \"h\" \"c\"))) (cl-defmethod pyim-imobjs-create (entered (scheme pyim-scheme-shuangpin)) (let ((keymaps (pyim-scheme-shuangpin-keymaps scheme)) (list (string-to-list (replace-regexp-in-string "-" "" entered))) results) (while list (let* ((sp-sm (pop list)) (sp-ym (pop list)) (sp-sm (when sp-sm (char-to-string sp-sm))) (sp-ym (when sp-ym (char-to-string sp-ym))) (sm (nth 1 (assoc sp-sm keymaps))) (ym (or (cdr (cdr (assoc sp-ym keymaps))) (list ""))) one-word-pinyins) (dolist (x ym) (let* ((y (concat sp-sm (or sp-ym " "))) (z (cadr (assoc y keymaps))) (py (if z (list "" z sp-sm sp-ym) (list sm x sp-sm sp-ym)))) (when (pyim-pinyin-valid-shuangpin-p (concat (nth 0 py) (nth 1 py))) (push py one-word-pinyins)))) (when (and one-word-pinyins (> (length one-word-pinyins) 0)) (push one-word-pinyins results)))) (pyim-imobjs-find-fuzzy (pyim-permutate-list (nreverse results)) scheme))) (cl-defmethod pyim-imobjs-create (entered (scheme pyim-scheme-xingma)) (let ((n (pyim-scheme-xingma-code-split-length scheme))) (let (output) (mapc (lambda (x) (while (not (string-empty-p x)) (if (< (length x) n) (progn (push x output) (setq x "")) (push (substring x 0 n) output) (setq x (substring x n))))) (split-string entered "'")) (list (nreverse output))))) (cl-defgeneric pyim-imobjs-find-fuzzy (imobjs scheme) "用于处理模糊音的函数。") (cl-defmethod pyim-imobjs-find-fuzzy (imobjs (_scheme pyim-scheme-quanpin)) "用于处理模糊音的函数。" (let (fuzzy-imobjs result1 result2) (dolist (imobj imobjs) (setq fuzzy-imobjs (pyim-permutate-list (mapcar #'pyim-pinyin-find-fuzzy imobj))) (push (car fuzzy-imobjs) result1) (setq result2 (append result2 (cdr fuzzy-imobjs)))) (append result1 result2))) ;; * Footer (provide 'pyim-imobjs) ;;; pyim-imobjs.el ends here pyim-5.3.3/pyim-punctuation.el0000644000175000017500000002240314412763714016213 0ustar dogslegdogsleg;;; pyim-punctuation.el --- punctuation tools for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-common) (defgroup pyim-punctuation nil "Punctuation libs for pyim." :group 'pyim) (defcustom pyim-punctuation-dict '(("'" "‘" "’") ("\"" "“" "”") ("_" "——") ("^" "…") ("]" "】") ("[" "【") ("@" "◎") ("?" "?") (">" "》") ("=" "=") ("<" "《") (";" ";") (":" ":") ("/" "、") ("." "。") ("-" "-") ("," ",") ("+" "+") ("*" "×") (")" ")") ("(" "(") ("&" "※") ("%" "%") ("$" "¥") ("#" "#") ("!" "!") ("`" "・") ("~" "~") ("}" "』") ("|" "÷") ("{" "『")) "标点符号表." :type '(repeat (cons (string :tag "半角标点") (choice :tag "全角标点" (list :tag "单个" string) (list :tag "成对" (string :tag "前") (string :tag "后")))))) (defcustom pyim-punctuation-half-width-functions nil "让 pyim 输入半角标点. 取值为一个函数列表,这个函数列表中的任意一个函数的运行结果为 t 时, pyim 输入半角标点,函数列表中每个函数都有一个参数:char ,表示 最后输入的一个字符,具体见: `pyim-process-select-handle-char' 。" :type '(repeat function)) (defvar pyim-punctuation-translate-p '(auto yes no) "这个变量的第一个元素的取值用于控制标点符号全角半角模式切换. 1. 当第一个元素为 \\='yes 时,输入全角标点。 2. 当第一个元素为 \\='no 时,输入半角标点。 3. 当第一个元素为 \\='auto 时,根据中英文环境,自动切换。") (defvar pyim-punctuation-escape-list (number-sequence ?0 ?9) "如果某些字符后面必须使用半角字符,可以将这些字符添加到此列表。 比如:当用户使用 org-mode 以及 markdown 等轻量级标记语言撰写文档 时,常常需要输入数字列表,比如: 1. item1 2. item2 3. item3 在这种情况下,数字后面输入句号必须是半角句号而不是全角句号。 这个变量设置为 nil 时,取消这个功能。") (defvar pyim-punctuation--pair-status '(("\"" nil) ("'" nil)) "成对标点符号切换状态.") (pyim-register-local-variables '(pyim-punctuation-translate-p pyim-punctuation--pair-status pyim-punctuation-escape-list pyim-punctuation-half-width-functions)) ;; ** 切换中英文标点符号 (defun pyim-punctuation-toggle () "Pyim 标点符号全角半角模式切换命令. 每次运行 `pyim-punctuation-toggle' 命令,都会调整变量 `pyim-punctuation-translate-p' 的取值,`pyim-process-select-handle-char' 根据 `pyim-process--punctuation-full-width-p' 函数的返回值,来决定是否转换标点 符号: 1. 当返回值为 \\='yes 时,`pyim-process-select-handle-char' 转换标点符号,从而输入全角标点。 2. 当返回值为 \\='no 时,`pyim-process-select-handle-char' 忽略转换,从而输入半角标点。 3. 当返回值为 \\='auto 时,根据中英文环境,自动切换。" (interactive) (setq pyim-punctuation-translate-p `(,@(cdr pyim-punctuation-translate-p) ,(car pyim-punctuation-translate-p))) (message (cl-case (car pyim-punctuation-translate-p) (yes "开启全角标点输入模式。") (no "开启半角标点输入模式。") (auto "开启全半角标点自动转换模式。")))) (defun pyim-punctuation-translate-at-point () "切换光标处标点的样式(全角 or 半角). 用户也可以使用命令 `pyim-punctuation-translate-at-point' 来切换 *光标前* 标点符号的样式。" (interactive) (let* ((current-char (char-to-string (preceding-char))) (punc-list (cl-some (lambda (x) (when (member current-char x) x)) pyim-punctuation-dict))) (when punc-list (if (equal current-char (car punc-list)) (pyim-punctuation-translate 'full-width) (pyim-punctuation-translate 'half-width))))) (defun pyim-punctuation-p (punct) "判断 PUNCT 是否是包含在 `pyim-punctuation-dict' 中的标点符号。" (cl-some (lambda (x) (when (member (char-to-string punct) x) x)) pyim-punctuation-dict)) (defun pyim-punctuation-position (punct) "返回 PUNCT 在 `pyim-punctuation-dict' 某一行中的位置。" (let* ((punc-list (cl-some (lambda (x) (when (member punct x) x)) pyim-punctuation-dict)) (punc-position (cl-position punct punc-list :test #'equal))) punc-position)) (defun pyim-punctuation-translate (&optional punct-style) "将光标前1个或前后连续成对的n个标点符号进行全角/半角转换. 当 PUNCT-STYLE 设置为 \\='full-width 时,所有的标点符号转换为全角符 号,设置为 \\='half-width 时,转换为半角符号。" (interactive) (let ((punc-list (pyim-flatten-tree pyim-punctuation-dict)) (punct-style (or punct-style (intern (completing-read "将光标处的标点转换为" '("full-width" "half-width"))))) ;; lnum : puncts on the left (before point) (lnum 0) ;; rnum : puncts on the right (after point) (rnum 0) (point (point)) last-puncts result) (catch 'break (while t (let ((str (pyim-char-after-to-string rnum))) (if (member str punc-list) (cl-incf rnum) (throw 'break nil))))) (catch 'break (while (<= lnum rnum) (let ((str (pyim-char-before-to-string lnum))) (if (member str punc-list) (cl-incf lnum) (throw 'break nil))))) ;; 右侧与左侧成对匹配 (setq rnum (min lnum rnum)) (setq last-puncts (buffer-substring (- point lnum) (+ point rnum))) ;; 删除旧的标点符号 (delete-char rnum) (delete-char (- 0 lnum)) (dolist (punct (split-string last-puncts "")) (dolist (puncts pyim-punctuation-dict) (let ((position (cl-position punct puncts :test #'equal))) (when position (cond ((eq punct-style 'full-width) (if (= position 0) (push (pyim-punctuation--return-proper-punct puncts) result) (push punct result))) ((eq punct-style 'half-width) (if (= position 0) (push punct result) (push (car puncts) result)))))))) (insert (string-join (reverse result))) (backward-char rnum))) (defun pyim-punctuation-return-proper-punct (punct-char) (let ((punc-list (assoc (char-to-string punct-char) pyim-punctuation-dict))) (pyim-punctuation--return-proper-punct punc-list))) (defun pyim-punctuation--return-proper-punct (punc-list &optional before) "返回合适的标点符号,PUNCT-LIST 为标点符号列表. 这个函数用于处理成对的全角标点符号,简单来说:如果第一次输入的标 点是: (\\=“) 时,那么下一次输入的标点就是 (\\=”) 。 PUNCT-LIST 格式类似: (\",\" \",\") 或者:(\"\\='\" \"\\=‘\" \"\\=’\") 当 BEFORE 为 t 时,只返回切换之前的结果,这个用来获取切换之前的 标点符号。 函数 `pyim-punctuation--return-proper-punct' 内部,我们使用变量 `pyim-punctuation--pair-status' 来记录 “成对” 中文标点符号的状态。" (let* ((str (car punc-list)) (punc (cdr punc-list)) (switch-p (cdr (assoc str pyim-punctuation--pair-status)))) (if (= (safe-length punc) 1) (car punc) (if before (setq switch-p (not switch-p)) (setf (cdr (assoc str pyim-punctuation--pair-status)) (not switch-p))) (if switch-p (car punc) (nth 1 punc))))) (defun pyim-punctuation-auto-half-width-p (char) "测试是否自动切换到半角标点符号。" (cl-some (lambda (x) (if (functionp x) (funcall x char) nil)) pyim-punctuation-half-width-functions)) (defun pyim-punctuation-escape-p (char) (member char pyim-punctuation-escape-list)) ;; * Footer (provide 'pyim-punctuation) ;;; pyim-punctuation.el ends here pyim-5.3.3/pyim.el0000644000175000017500000005230714476561504013655 0ustar dogslegdogsleg;;; pyim.el --- A Chinese input method support quanpin, shuangpin, wubi, cangjie and rime. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2015-2021 Free Software Foundation, Inc. ;; Author: Ye Wenbin ;; Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Version: 5.3.3 ;; Keywords: convenience, Chinese, pinyin, input-method ;; Package-Requires: ((emacs "27.1") (async "1.6") (xr "1.13")) ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 核心代码 :code: ;; ** require + defcustom + defvar (require 'cl-lib) (require 'help-mode) (require 'pyim-autoselector) (require 'pyim-common) (require 'pyim-cstring) (require 'pyim-dhashcache) (require 'pyim-indicator) (require 'pyim-page) (require 'pyim-preview) (require 'pyim-process) (require 'pyim-scheme) (require 'subr-x) (defgroup pyim nil "Pyim is a Chinese input method support quanpin, shuangpin, wubi and cangjie." :group 'leim) (defcustom pyim-select-word-by-number t "使用数字键来选择词条. 如果设置为 nil, 将直接输入数字,适用于使用数字做为 编码的输入法。" :type 'boolean) ;;;###autoload (defvar pyim-title "PYIM ") (defvar pyim-load-hook nil) (defvar pyim-activate-hook nil) (defvar pyim-deactivate-hook nil) (defvar pyim-mode-map (let ((map (make-sparse-keymap)) (i ?\ )) (while (< i 127) (define-key map (char-to-string i) #'pyim-self-insert-command) (setq i (1+ i))) (setq i 128) (while (< i 256) (define-key map (vector i) #'pyim-self-insert-command) (setq i (1+ i))) (dolist (i (number-sequence 0 9)) (define-key map (kbd (number-to-string i)) (lambda () (interactive) (pyim-select-word-by-number i)))) (dolist (x '(("" . 1) ("" . 2) ("" . 3) ("" . 4))) (define-key map (kbd (car x)) (lambda () (interactive) (pyim-select-char-in-word-by-number (cdr x))))) (define-key map " " #'pyim-select-word) (define-key map (kbd "C-SPC") #'pyim-select-word-simple) (define-key map [backspace] #'pyim-delete-backward-char) (define-key map [delete] #'pyim-delete-forward-char) (define-key map "\C-d" #'pyim-delete-forward-char) (define-key map [M-backspace] #'pyim-delete-backward-imelem) (define-key map [M-delete] #'pyim-delete-forward-imelem) (define-key map [C-backspace] #'pyim-delete-backward-imelem) (define-key map [C-delete] #'pyim-delete-forward-imelem) (define-key map [?\t] #'pyim-toggle-assistant-scheme) (define-key map (kbd "TAB") #'pyim-toggle-assistant-scheme) (define-key map "\177" #'pyim-delete-backward-char) (define-key map "\C-f" #'pyim-forward-point) (define-key map "\C-b" #'pyim-backward-point) (define-key map "\M-f" #'pyim-forward-imelem) (define-key map "\M-b" #'pyim-backward-imelem) (define-key map "\C-e" #'pyim-end-of-line) (define-key map "\C-a" #'pyim-beginning-of-line) (define-key map "=" #'pyim-next-page) (define-key map "-" #'pyim-previous-page) (define-key map "\C-n" #'pyim-next-word) (define-key map "\C-p" #'pyim-previous-word) (define-key map "\M-n" #'pyim-next-page) (define-key map "\M-p" #'pyim-previous-page) (define-key map "\C-m" #'pyim-quit-no-clear) (define-key map [return] #'pyim-quit-no-clear) (define-key map "\C-c" #'pyim-quit-clear) (define-key map "\C-g" #'pyim-quit-clear) map) "Pyim 的 Keymap.") (cl-defmethod pyim-process-get-mode-map () pyim-mode-map) ;; ** pyim 输入法定义 (defun pyim-input-method (key) "得到需要插入到 buffer 的字符串, 并将其插入到待输入 buffer. 这个函数会处理用户输入的字符,并最终的得到需要插入 buffer 的字符 串。这个字符串会被分解为 event list, 通过 emacs 低层函数 `read-event' 来将这些 list 插入到 *待输入buffer*。" (if (or buffer-read-only overriding-terminal-local-map overriding-local-map) (list key) ;; (message "call with key: %S" key-or-string) (with-silent-modifications (unwind-protect (let ((input-string (pyim-process-input-method key))) ;; (message "input-string: %s" input-string) (when (and (stringp input-string) (> (length input-string) 0)) (if input-method-exit-on-first-char (list (aref input-string 0)) (mapcar #'identity input-string)))) (pyim-process-terminate))))) ;; ** Pyim 输入法注册 ;;;###autoload (register-input-method "pyim" "UTF-8" #'pyim-activate pyim-title "") ;; ** PYim 输入法启动功能 ;;;###autoload (defun pyim-activate (&optional _args) "pyim 启动函数. pyim 是使用 `pyim-activate' 来启动输入法,这个命令主要做如下工作: 1. 重置所有的 local 变量。 2. 创建汉字到拼音和拼音到汉字的 hash table。 3. 创建词库缓存 dcache. 4. 运行 hook: `pyim-load-hook'。 5. 将 `pyim--kill-emacs-hook-function' 命令添加到 `kill-emacs-hook' , emacs 关闭 之前将用户选择过的词生成的缓存和词频缓存保存到文件,供以后使用。 6. 设定变量: 1. `input-method-function' 2. `deactivate-current-input-method-function' 7. 运行 `pyim-activate-hook' pyim 使用函数 `pyim-activate' 启动输入法的时候,会将变量 `input-method-function' 设置为 `pyim-input-method' ,这个变量会影 响 `read-event' 的行为。 当输入字符时,`read-event' 会被调用,`read-event' 调用的过程中, 会执行 `pyim-input-method' 这个函数。" (interactive) ;; 启动 pyim 需要的 daemon (pyim-process-start-daemon) ;; 初始化 dcache. (pyim-process-init-dcaches) ;; 启动或者重启的时候,退出辅助输入法。 (pyim-scheme-disable-assistant) (run-hooks 'pyim-load-hook) ;; Make sure personal or other dcache are saved to file before kill emacs. (add-hook 'kill-emacs-hook #'pyim--kill-emacs-hook-function) (setq deactivate-current-input-method-function #'pyim-deactivate) ;; If we are in minibuffer, turn off the current input method ;; before exiting. (when (eq (selected-window) (minibuffer-window)) (add-hook 'minibuffer-exit-hook #'pyim-exit-from-minibuffer)) (run-hooks 'pyim-activate-hook) (setq-local input-method-function #'pyim-input-method) nil) (defun pyim--kill-emacs-hook-function () "Pyim function which is used in `kill-emacs-hook'." (pyim-process-save-dcaches t) t) ;; ** 取消激活功能 (defun pyim-deactivate () "取消 pyim 的激活状态." (interactive) (pyim-kill-local-variables) (kill-local-variable 'input-method-function) (pyim-process-stop-daemon) (run-hooks 'pyim-deactivate-hook)) ;; ** pyim 从 minibuffer 退出功能 (defun pyim-exit-from-minibuffer () "Pyim 从 minibuffer 退出." (deactivate-input-method) (when (<= (minibuffer-depth) 1) (remove-hook 'minibuffer-exit-hook 'pyim-exit-from-minibuffer))) ;; ** pyim 重启功能 (defun pyim-restart () "重启 pyim,不建议用于编程环境. 这个函数用于重启 pyim,其过程和 `pyim-activate' 类似,只是在输入法重 启之前,询问用户,是否保存个人词频信息。" (interactive) (let ((save-personal-dcache (yes-or-no-p "重启 pyim 前,需要保存个人词频信息吗? "))) (pyim-restart-1 save-personal-dcache))) (defun pyim-restart-1 (&optional save-personal-dcache _refresh-common-dcache) "重启 pyim,用于编程环境. 当 SAVE-PERSONAL-DCACHE 是 non-nil 时,保存个人词库文件。 REFRESH-COMMON-DCACHE 已经废弃,不要再使用了。" (pyim-process-save-dcaches save-personal-dcache) (pyim-process-init-dcaches :force)) ;; ** 升级功能 (defun pyim-upgrade () "升级 pyim 功能。" (interactive) (pyim-dcache-upgrade)) ;; ** 键盘输入处理功能 (defun pyim-self-insert-command () "Pyim 默认的 self-insert-command." (interactive "*") (cond ((pyim-process-input-chinese-p) (pyim-process-with-entered-buffer ;; 一定要注意,point 可能不在 point-min, 或者 point-max. 因为用 ;; 户可能通过命令移动了 entered 中的 point。 (insert (char-to-string last-command-event))) (pyim-process-run)) ((pyim-process-get-candidates) (pyim-process-select-word-and-last-char)) (t (pyim-process-select-last-char)))) (pyim-process-register-self-insert-command 'pyim-self-insert-command) ;; ** 加词功能 (defalias 'pyim-create-word-at-point #'pyim-process-create-word-at-point) (defun pyim-create-2cchar-word-at-point () "将光标前2个中文字符组成的字符串加入个人词库。" (interactive) (pyim-create-word-at-point 2)) (defun pyim-create-3cchar-word-at-point () "将光标前3个中文字符组成的字符串加入个人词库。" (interactive) (pyim-create-word-at-point 3)) (defun pyim-create-4cchar-word-at-point () "将光标前4个中文字符组成的字符串加入个人词库。" (interactive) (pyim-create-word-at-point 4)) (defun pyim-create-word-from-selection () "Add the selected text as a Chinese word into the personal dictionary." (interactive) (when (region-active-p) (let ((string (buffer-substring-no-properties (region-beginning) (region-end)))) (if (> (length string) 6) (error "PYIM: 所选词条太长。") (if (not (string-match-p "^\\cc+\\'" string)) (error "PYIM: 所选词条包含非中文字符。") (pyim-process-create-word string) (message "PYIM: 将词条 %S 加入词库。" string))) (deactivate-mark) ;; NOTE: 这里必须返回 t, 因为这个函数的返回结果会被用来做为判断条件。 t))) ;; ** 导入词条功能 (defun pyim-import-words-and-counts (file &optional merge-method silent) "从 FILE 中导入词条以及词条对应的词频信息。 导入的文件结构类似: ;;; -*- coding: utf-8-unix -*- ;; 词条 计数 对应编码(可选) 你好 247 这是 312 MERGE-METHOD 是一个函数,这个函数需要两个数字参数,代表词条在词频 缓存中的词频和待导入文件中的词频,函数返回值做为合并后的词频使用, 默认方式是:取两个词频的最大值。" (interactive "F导入词条和词频信息文件: ") ;; 导入词条和词频之前需要加载 dcaches. (when (or silent (yes-or-no-p "PYIM 词条导入注意事项: 1. 这个命令对多音字处理比较粗糙,可能会导入一些不合常理的词条记录, (比如:ying-xing 银行),但不影响 PYIM 正常使用。 2. 这个命令也可以用于形码输入法,比如:五笔,不过需要形码输入法有 编码反查功能。 => 确定继续导入吗?")) (pyim-process-init-dcaches) (with-temp-buffer (let ((coding-system-for-read 'utf-8-unix)) (insert-file-contents file)) (goto-char (point-min)) (forward-line 1) (while (not (eobp)) (let* ((content (pyim-dline-parse)) (word (car content)) (count (string-to-number (or (car (cdr content)) "0"))) (criteria (car (cdr (cdr content))))) (pyim-process-create-word word nil (lambda (x) (funcall (or merge-method #'max) (or x 0) count)) criteria) (unless silent (message "* 导入 %S" word))) (forward-line 1))) ;; 保存一下用户选择过的词生成的缓存和词频缓存, ;; 因为使用 async 机制更新 dcache 时,需要从 dcache 文件 ;; 中读取变量值, 然后再对用户选择过的词生成的缓存排序,如果没 ;; 有这一步骤,导入的词条就会被覆盖。 (pyim-process-save-dcaches t) ;; 更新相关的 dcache (pyim-process-update t) (message "PYIM: 词条和词频信息导入完成!"))) ;; ** 导出功能 (defun pyim-export-words-and-counts (file &optional confirm ignore-counts) "将个人词条以及词条对应的词频信息导出到文件 FILE. 如果 FILE 为 nil, 提示用户指定导出文件位置, 如果 CONFIRM 为 non-nil,文件存在时将会提示用户是否覆盖,默认为覆盖模式" (interactive "F将词条和词频信息导出到文件: ") (pyim-dcache-init-variables) (pyim-dcache-export-words-and-counts file confirm ignore-counts) (message "PYIM: 词条和词频信息导出完成。")) (defun pyim-export-personal-words (file &optional confirm) "将用户的个人词条导出为 pyim 词库文件. 如果 FILE 为 nil, 提示用户指定导出文件位置, 如果 CONFIRM 为 non-nil, 文件存在时将会提示用户是否覆盖,默认为覆盖模式。" (interactive "F将个人词条导出到文件:") (pyim-dcache-init-variables) (pyim-dcache-export-personal-words file confirm) (message "PYIM: 个人词条导出完成。")) ;; ** 删词功能 (defun pyim-delete-words-in-file (file) "从个人词库缓存中批量删除 FILE 文件中列出的词条. FILE 的格式与 `pyim-dcache-export' 生成的文件格式相同, 另外这个命令也可以识别没有词频的行,比如: ;;; -*- coding: utf-8-unix -*- 词条1 词条2" (interactive "F记录待删词条的文件: ") (with-temp-buffer (let ((coding-system-for-read 'utf-8-unix)) (insert-file-contents file)) (goto-char (point-min)) (forward-line 1) (while (not (eobp)) (let ((word (car (pyim-dline-parse)))) (when (and word (not (pyim-string-match-p "\\CC" word))) (pyim-process-delete-word word))) (forward-line 1))) (message "PYIM: 批量删词完成!")) (defun pyim-delete-last-word () "从个人词库中删除最新创建的词条。" (interactive) (let ((word (pyim-process-last-created-word))) (when word (pyim-process-delete-word word) (message "PYIM: 将词条 %S 从个人词库中删除!" word)))) (defalias 'pyim-delete-word-at-point #'pyim-process-delete-word-at-point) (defun pyim-delete-word () "从个人词库中删除词条。" (interactive) (cond (mark-active (let ((string (buffer-substring-no-properties (region-beginning) (region-end)))) (when (and (< (length string) 6) (> (length string) 0)) (pyim-process-delete-word string) (message "将词条 %S 从个人词库中删除。" string) (deactivate-mark)))) (t (let ((words (completing-read-multiple "请选择需要删除的词条(可多选): " (pyim-process-last-created-words)))) (dolist (word words) (pyim-process-delete-word word) (message "将词条 %S 从个人词库中删除。" word)))))) ;; ** 选词功能 (defun pyim-select-word-simple () "从选词框中选择当前词条. 这个函数与 `pyim-select-word' 的区别是: 这个函数不会将选择的词条加入个人词库,主要的使用场景是: 当用户需要输入一个生僻字时,输入包含该字的一个词条, 然后再删除不需要的字,由于这个词条不是常用词条,所以 不需要保存到个人词库。" (interactive) (if (pyim-process-get-candidates) (pyim-process-select-word-without-save) (pyim-process-select-last-char))) (defun pyim-select-word () "从选词框中选择当前词条,然后删除该词条对应拼音。" (interactive) (if (pyim-process-get-candidates) (pyim-process-select-word (pyim-scheme-current)) ;; 如果没有选项,输入空格 (pyim-process-select-last-char))) (defun pyim-select-word-by-number (&optional num) "使用数字编号来选择对应的词条。" (interactive) (if (or pyim-select-word-by-number num) (pyim-select-word-by-number-1 num) ;; 有些输入法使用数字键编码,这种情况下,数字键就 ;; 不能用来选词了。 (call-interactively #'pyim-self-insert-command))) (defun pyim-select-word-by-number-1 (num) (if (and (pyim-process-get-candidates) (pyim-page-plan-to-select-word num)) (pyim-process-select-word (pyim-scheme-current)) (pyim-process-select-last-char))) (defun pyim-select-char-in-word-by-number (&optional n) "以词定字功能。" (interactive) (pyim-process-plan-to-select-char-in-word (1- (or n 1))) (pyim-process-select-word (pyim-scheme-current))) ;; ** 翻页和翻词功能 (defalias 'pyim-previous-page #'pyim-page-previous-page) (defalias 'pyim-next-page #'pyim-page-next-page) (defalias 'pyim-previous-word #'pyim-page-previous-word) (defalias 'pyim-next-word #'pyim-page-next-word) ;; ** 取消当前输入功能 (defun pyim-quit-clear () "取消当前输入的命令." (interactive) (pyim-process-select-nothing)) ;; ** 字母上屏功能 (defun pyim-quit-no-clear () "字母上屏命令." (interactive) (pyim-process-select-entered)) ;; ** 中英文输入模式切换 (defalias 'pyim-toggle-input-ascii #'pyim-process-toggle-input-ascii) ;; ** 主辅输入法切换功能 (defun pyim-toggle-assistant-scheme () "临时切换到辅助输入法. 这个功能一般用于五笔等形码输入法,在忘记编码的时候临时用拼音输入 中文。" (interactive) (if (pyim-process-without-entered-p) (pyim-process-select-last-char) (pyim-scheme-toggle-assistant) (pyim-process-run))) ;; ** PYIM 输入操作命令 (defun pyim-forward-point () "光标前移" (interactive) (pyim-process-with-entered-buffer (forward-char)) (pyim-process-run)) (defun pyim-backward-point () "光标后移" (interactive) (pyim-process-with-entered-buffer (backward-char)) (pyim-process-run)) (defun pyim-backward-imelem (&optional search-forward) "光标向后移动一个 imelem 对应的字符串 在全拼输入法中,就是向前移动一个拼音" (interactive) (let ((position (pyim-process-next-imelem-position 1 search-forward))) (pyim-process-with-entered-buffer (goto-char position)) (pyim-process-run))) (defun pyim-forward-imelem () "光标向前移动一个 imelem 对应的字符串" (interactive) (pyim-backward-imelem t)) (defun pyim-end-of-line () "光标移至行尾" (interactive) (pyim-process-with-entered-buffer (end-of-line)) (pyim-process-run)) (defun pyim-beginning-of-line () "光标移至行首" (interactive) (pyim-process-with-entered-buffer (beginning-of-line)) (pyim-process-run)) (defun pyim-delete-backward-char (&optional n) "向后删除1个字符" (interactive) (pyim-process-with-entered-buffer (delete-char (- 0 (or n 1)))) (if (pyim-process-without-entered-p) (pyim-process-select-nothing) (pyim-process-run))) (defun pyim-delete-forward-char () "向前删除1个字符" (interactive) (pyim-delete-backward-char -1)) (defun pyim-delete-backward-imelem (&optional search-forward) "向后删除一个 imelem 对应的字符串" (interactive) (let ((position (pyim-process-next-imelem-position 1 search-forward))) (pyim-process-with-entered-buffer (delete-region (point) position)) (pyim-process-run))) (defun pyim-delete-forward-imelem () "向前删除一个 imelem 对应的字符串" (interactive) (pyim-delete-backward-imelem t)) ;; ** 金手指功能 ;;;###autoload (defun pyim-convert-string-at-point (&optional _) "将光标前的用户输入的字符串转换为中文." (interactive "P") (pyim--activate-pyim) (or (pyim-create-word-from-selection) (pyim-process-trigger-feature-run-p) (pyim-process-feed-entered-at-point-into-pyim) (message "PYIM: 命令 `pyim-convert-string-at-point' 没有起作用!"))) (defun pyim--activate-pyim () "如果当前输入法设置为 pyim, 就激活它。" (unless (equal input-method-function 'pyim-input-method) (activate-input-method 'pyim))) ;; ** 编码反查功能 (defun pyim-search-word-code () "选择词条,然后反查它的 code。" (interactive) (when (region-active-p) (let* ((string (buffer-substring-no-properties (region-beginning) (region-end))) codes) (if (not (string-match-p "^\\cc+\\'" string)) (error "PYIM: 不是纯中文字符串。") (setq codes (pyim-cstring-to-codes string (pyim-scheme-current))) (if codes (message "PYIM (%S): %S -> %S" pyim-default-scheme string codes) (message "PYIM: 没有找到 %S 对应的编码。" string))) (deactivate-mark)))) ;; ** pyim 探针 (require 'pyim-probe) ;; ** pyim 云输入法 (require 'pyim-cloudim) ;; * Footer (provide 'pyim) ;;; pyim.el ends here pyim-5.3.3/pyim-process.el0000644000175000017500000012263314412763713015325 0ustar dogslegdogsleg;;; pyim-process.el --- Process of pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-common) (require 'pyim-scheme) (require 'pyim-dcache) (require 'pyim-entered) (require 'pyim-imobjs) (require 'pyim-codes) (require 'pyim-candidates) (require 'pyim-outcome) (require 'pyim-punctuation) (require 'pyim-cstring) (defgroup pyim-process nil "Process for pyim." :group 'pyim) (defcustom pyim-english-input-switch-functions nil "让 pyim 开启英文输入功能. 这个变量的取值为一个函数列表,这个函数列表中的任意一个函数的 运行结果为 t 时,pyim 开启英文输入功能。" :type '(repeat function)) (defcustom pyim-force-input-chinese-functions nil "让 pyim 强制输入中文. 这个变量的取值为一个函数列表,这个函数列表中的任意一个函数的运行 结果为 t 时,pyim 将强制输入中文功能,无视 `pyim-english-input-switch-functions' 的设置." :type '(repeat function)) (defvaralias 'pyim-autoselector 'pyim-process-autoselector) (defcustom pyim-process-autoselector nil "当前启用的自动上屏器列表. 自动上屏器是一个函数。假设用户已经输入 \"nihao\", 并按下 \"m\" 键, 那么当前entered 就是 \"nihaom\". 上次 entered 是 \"nihao\". 那么 返回值有3种情况(优先级按照下面的顺序): 1. (:select last :replace-with \"xxx\") 自动上屏上次 entered (nihao) 的第一个候选词,m 键下一轮处理。 2. (:select current :replace-with \"xxx\") 自动上屏当前 entered (nihaom) 的第一个候选词。 3. nil 不自动上屏。 如果 :replace-with 设置为一个字符串,则选择最终会被这个字符串替代。 注意:多个 autoselector 函数运行时,最好不要相互影响,如果相互有 影响,需要用户自己管理。" :type '(repeat function)) (defcustom pyim-process-run-delay 0.5 "延迟多少秒开始延迟获取词条。" :type 'number) (defcustom pyim-select-finish-hook nil "Pyim 选词完成时运行的 hook." :type 'hook) (defvar pyim-process-ui-init-hook nil "Hook used to run ui init functions.") (defvar pyim-process-ui-refresh-hook nil "Hook used to run ui refresh functions.") (defvar pyim-process-ui-hide-hook nil "Hook used to run ui hide functions.") (defvar pyim-process-start-daemon-hook nil "Pyim start daemon hook.") (defvar pyim-process-stop-daemon-hook nil "Pyim stop daemon hook.") (defvar pyim-process--self-insert-commands nil "保存所有的 self insert command.") (defvar pyim-process--input-ascii nil "是否开启 pyim 英文输入模式.") (defvar pyim-process--force-input-chinese nil "是否强制开启中文输入模式. 这个变量只用于 `pyim-convert-string-at-point', 不要 在其它地方使用。") (defvar pyim-process--translating nil "记录是否在转换状态.") (defvar pyim-process--imobjs nil "Imobj (Input method object) 组成的 list. imobj 在 pyim 里面的概念,类似与编译器里面的语法树, 它代表 pyim 输入的字符串 entered 解析得到的一个结构化对象, 以全拼输入法的为例: 1. entered: nihaoma 2. imobj: ((\"n\" \"i\" \"n\" \"i\") (\"h\" \"ao\" \"h\" \"ao\") (\"m\" \"a\" \"m\" \"a\")) 而 imobjs 是 imobj 组成的一个列表,因为有模糊音等概念的存在,一个 entered 需要以多种方式或者多步骤解析,得到多种可能的 imobj, 这些 imobj 组合构成在一起,构成了 imobjs 这个概念。比如: 1. entered: guafeng (设置了模糊音 en -> eng) 2. imobj-1: ((\"g\" \"ua\" \"g\" \"ua\") (\"f\" \"en\" \"f\" \"eng\")) 3. imobj-2: ((\"g\" \"ua\" \"g\" \"ua\") (\"f\" \"eng\" \"f\" \"eng\")) 4. imobjs: (((\"g\" \"ua\" \"g\" \"ua\") (\"f\" \"en\" \"f\" \"eng\")) ((\"g\" \"ua\" \"g\" \"ua\") (\"f\" \"eng\" \"f\" \"eng\"))) 这个变量用来保存解析得到的 imobjs。 解析完成之后,pyim 会为每一个 imobj 创建对应 code 字符串, 然后在词库 中搜索 code 字符串来得到所需要的词条,最后使用特定的方式将得到的 词条组合成一个候选词列表:`pyim-candidates' 并通过 pyim-page 相关 功能来显示选词框,供用户选择词条,比如: 1. imobj: ((\"g\" \"ua\" \"g\" \"ua\") (\"f\" \"en\" \"f\" \"en\")) 2. code: gua-fen 从上面的说明可以看出,imobj 本身也是有结构的: 1. imobj: ((\"g\" \"ua\" \"g\" \"ua\") (\"f\" \"en\" \"f\" \"en\")) 我们将 (\"g\" \"ua\" \"g\" \"ua\") 这些子结构,叫做 imelem (IM element), *大 多数情况下*, 一个 imelem 能够代表一个汉字,这个概念在编辑 entered 的时候,非常有用。 另外要注意的是,不同的输入法, imelem 的内部结构是不一样的,比如: 1. quanping: (\"g\" \"ua\" \"g\" \"ua\") 2. shuangpin: (\"h\" \"ao\" \"h\" \"c\") 3. wubi: (\"aaaa\")") (defvar pyim-process--code-criteria nil "用于 code 选取的基准字符串。 当获取到一个词条的多个 codes 时, pyim 会将所有的 codes 与这个字 符串进行比较,然后选择一个与这个字符串最相似的 code. 这个变量主要用于全拼和双拼输入法的多音字矫正,其取值一般使用用户 输入生成的 imobjs 转换得到,保留了用户原始输入的许多信息。") (defvar pyim-process--candidates nil "所有备选词条组成的列表.") (defvar pyim-process--last-candidates nil "上一轮备选词条列表,这个变量主要用于 autoselector 机制.") (defvar pyim-process--word-position nil "当前选择的词条在 `pyim-candidates’ 中的位置. 细节信息请参考 `pyim-page--refresh' 的 docstring.") (defvar pyim-process--char-position-in-word nil "“以词定字”功能中“字”在“词”中的位置.") (defvar pyim-process--run-delay-timer nil "异步处理 entered 时,使用的 timer.") (defvar pyim-process--last-created-words nil "记录最近创建的词条, 用于实现快捷删词功能: `pyim-delete-last-word' .") (pyim-register-local-variables '(pyim-process--input-ascii pyim-process--translating pyim-process--imobjs pyim-process--candidates pyim-process--word-position)) ;; ** pyim-input-method 核心函数 (defun pyim-process-input-method (key) "`pyim-process-input-method' 是 `pyim-input-method' 内部使用的函数。 这个函数比较复杂,作许多低层工作,但它的一个重要流程是: 1. 使用函数 `read-key-sequence' 得到 key-sequence 2. 使用函数 `lookup-key' 查询 `pyim-mode-map' 中,与上述 key-sequence 对应 的命令。 3. 如果查询得到的命令是 self-insert-command 时,调用这个函数。 4. 这个函数最终会返回需要插入到 buffer 的字符串。 这个部份的代码涉及许多 emacs 低层函数,相对复杂,不容易理解,有兴 趣的朋友可以参考 elisp 手册相关章节: 1. Invoking the Input Method 2. Input Methods 3. Miscellaneous Event Input Features 4. Reading One Event" ;; Check the possibility of translating KEY. ;; If KEY is nil, we can anyway start translation. (pyim-process-ui-init) (if (or (integerp key) (null key)) ;; OK, we can start translation. (let* ((echo-keystrokes 0) (help-char nil) (mode-map (pyim-process-get-mode-map)) (overriding-terminal-local-map mode-map) (input-method-function nil) (input-method-use-echo-area nil) (modified-p (buffer-modified-p)) last-command-event last-command this-command) (pyim-process--init-cleanup) (when key (pyim-add-unread-command-events key)) (while (pyim-process--translating-p) (set-buffer-modified-p modified-p) (let* ((keyseq (read-key-sequence nil nil nil t)) (cmd (lookup-key mode-map keyseq))) ;; (message "key: %s, cmd:%s\nlcmd: %s, lcmdv: %s, tcmd: %s" ;; key cmd last-command last-command-event this-command) (if (if key (commandp cmd) (pyim-process-self-insert-command-p cmd)) (progn ;; (message "keyseq: %s" keyseq) (setq last-command-event (aref keyseq (1- (length keyseq))) last-command this-command this-command cmd) (setq key t) (condition-case-unless-debug err (call-interactively cmd) (error (message "pyim 出现错误: %S , 开启 debug-on-error 后可以了解详细情况。" err) (beep)))) ;; KEYSEQ is not defined in the translation keymap. ;; Let's return the event(s) to the caller. (pyim-add-unread-command-events (this-single-command-raw-keys) t) ;; (message "unread-command-events: %s" unread-command-events) (pyim-process-terminate)))) ;; (message "return: %s" (pyim-process-get-select-result)) (pyim-process-get-select-result)) ;; Since KEY doesn't start any translation, just return it. ;; But translate KEY if necessary. (char-to-string key))) (cl-defgeneric pyim-process-get-mode-map () "获取 pyim mode map.") (defun pyim-process--init-cleanup () (pyim-entered-erase-buffer) (pyim-process--set-translating-flag t) (setq pyim-process--char-position-in-word nil) (pyim-outcome-erase)) (defun pyim-process--set-translating-flag (value) (setq pyim-process--translating value)) (defun pyim-process--translating-p () pyim-process--translating) (defun pyim-process-self-insert-command-p (cmd) "测试 CMD 是否是一个 pyim self insert command." (member cmd pyim-process--self-insert-commands)) (defun pyim-process-register-self-insert-command (command) (cl-pushnew command pyim-process--self-insert-commands)) (defun pyim-process-terminate () "Terminate the translation of the current key." (pyim-process-terminate-really (pyim-scheme-current))) (cl-defgeneric pyim-process-terminate-really (scheme) "Terminate the translation of the current key.") (cl-defmethod pyim-process-terminate-really (_scheme) (pyim-process--set-translating-flag nil) (pyim-entered-erase-buffer) (setq pyim-process--code-criteria nil) (setq pyim-process--force-input-chinese nil) (setq pyim-process--candidates nil) (setq pyim-process--last-candidates nil) (pyim-process--run-delay-timer-reset) (pyim-process-ui-hide)) ;; ** Dcache,UI 和 daemon 相关 (defun pyim-process-ui-init () "初始化 pyim 相关 UI." (run-hooks 'pyim-process-ui-init-hook)) (cl-defgeneric pyim-process-ui-position () "返回选词框等 UI 放置的位置。" (point)) (defun pyim-process-init-dcaches (&optional force) "PYIM 流程,词库相关的初始化工作。" (pyim-recreate-local-variables) (pyim-pymap-cache-create) (pyim-dcache-init-variables) (pyim-dcache-update force)) (defun pyim-process-save-dcaches (&optional force) "PYIM 流程,保存 dcache." (when force (pyim-dcache-save-caches))) (defun pyim-process-update (&optional force) (when pyim-dcache-auto-update (pyim-dcache-update force))) (defun pyim-process-start-daemon () "启动 pyim 流程需要的 daemon." (run-hooks 'pyim-process-start-daemon-hook)) (defun pyim-process-stop-daemon () "关闭 pyim 流程已经启动的 daemon." (interactive) (run-hooks 'pyim-process-stop-daemon-hook)) ;; ** 输入相关 (defmacro pyim-process-with-entered-buffer (&rest forms) "PYIM 流程的输入保存在一个 buffer 中,使用 FORMS 处理这个 buffer 中的信息。" (declare (indent 0) (debug t)) `(pyim-entered-with-entered-buffer (ignore-errors ,@forms))) (defun pyim-process-next-imelem-position (num &optional search-forward start) "从 `pyim-entered--buffer' 的当前位置,找到下一个或者下 NUM 个 imelem 对应的位置 如果 SEARCH-FORWARD 为 t, 则向前搜索,反之,向后搜索。" (pyim-entered-with-entered-buffer (let* ((scheme (pyim-scheme-current)) (start (or start (point))) (end-position start) (string (buffer-substring-no-properties (point-min) start)) (orig-imobj-len (length (car (pyim-imobjs-create string scheme)))) imobj pos) (if search-forward ;; "ni|haoshijie" -> "nihao|shijie" (progn (setq pos (point-max)) (while (and (> pos start) (= end-position start)) (setq string (buffer-substring-no-properties (point-min) pos) imobj (car (pyim-imobjs-create string scheme))) (if (>= (+ orig-imobj-len num) (length imobj)) (setq end-position pos) (cl-decf pos)))) ;; "nihao|shijie" -> "ni|haoshijie" (if (<= orig-imobj-len num) (setq end-position (point-min)) (setq pos start) (while (and (>= pos (point-min)) (= end-position start)) (setq string (buffer-substring-no-properties (point-min) pos) imobj (car (pyim-imobjs-create string scheme))) (if (= (- orig-imobj-len num) (length imobj)) (setq end-position pos) (cl-decf pos))))) end-position))) (defun pyim-process--string-at-region-or-point () (if mark-active (buffer-substring-no-properties (region-beginning) (region-end)) (buffer-substring (point) (line-beginning-position)))) (defun pyim-process-feed-entered-at-point-into-pyim () (let* ((entered-info (pyim-process--find-entered-at-point)) (entered (nth 0 entered-info)) (char-num-need-delete (nth 1 entered-info))) (when entered-info (pyim-process--delete-region-or-chars char-num-need-delete) (pyim-process--feed-entered-into-pyim entered) ;; NOTE: 这里必须返回 t, 因为这个函数的返回结果会被作为判断条件使用。 t))) (defun pyim-process--find-entered-at-point () "从光标处提取一个有效的 entered 字符串." (let* ((case-fold-search nil) (scheme (pyim-scheme-current)) (first-chars (pyim-scheme-first-chars scheme)) (rest-chars (pyim-scheme-rest-chars scheme)) (regexp-used-to-extract-entered (format "[%s]+ *$" (cl-delete-duplicates (concat first-chars rest-chars "'-")))) (string (pyim-process--string-at-region-or-point))) (when (string-match regexp-used-to-extract-entered string) (let* ((entered (match-string 0 string)) ;; 一些编程语言使用单引号做为字符串的标记,这里需要特殊处理。 (entered (replace-regexp-in-string "^[-']" "" entered)) (backward-delete-char-number (length entered)) (entered (replace-regexp-in-string " +" "" entered))) (list entered backward-delete-char-number))))) (defun pyim-process--delete-region-or-chars (&optional num) "删除 region 或者光标之前 NUM 个字符。" (if mark-active (delete-region (region-beginning) (region-end)) (when (and (numberp num) (> num 0)) (delete-char (- 0 num))))) (defun pyim-process--feed-entered-into-pyim (entered) (when (and (stringp entered) (> (length entered) 0)) (pyim-add-unread-command-events entered) (pyim-process--force-input-chinese))) (defun pyim-process--force-input-chinese () "让 pyim 强制输入中文,忽略所有探针函数。" (setq pyim-process--force-input-chinese t)) ;; ** 中英文切换相关 (defun pyim-process-toggle-input-ascii () "pyim 切换中英文输入模式, 同时调整标点符号样式。" (interactive) (setq pyim-process--input-ascii (not pyim-process--input-ascii))) (defun pyim-process-input-chinese-p () "确定 pyim 是否需要启动中文输入模式." (let* ((scheme (pyim-scheme-current)) (first-chars (pyim-scheme-first-chars scheme)) (rest-chars (pyim-scheme-rest-chars scheme)) (entered (pyim-entered-get 'point-before))) (and (pyim-process--input-chinese-predicate-1) (pyim-process--input-chinese-predicate-2 last-command-event entered first-chars rest-chars)))) (defun pyim-process--input-chinese-predicate-1 () "`pyim-process-input-chinese-p' 内部函数,测试环境。" (or (pyim-process--force-input-chinese-p) (and (not pyim-process--input-ascii) (not (pyim-process-auto-switch-english-input-p))))) (defun pyim-process--force-input-chinese-p () "判断是否强制输入中文,这个函数主要处理变量: `pyim-force-input-chinese-functions'." (let ((func-or-list pyim-force-input-chinese-functions)) (or pyim-process--force-input-chinese (cl-some (lambda (x) (when (functionp x) (funcall x))) (cond ((functionp func-or-list) (list func-or-list)) ((listp func-or-list) func-or-list) (t nil)))))) (defun pyim-process-auto-switch-english-input-p () "判断是否 *根据环境自动切换* 为英文输入模式,这个函数处理变量: `pyim-english-input-switch-functions'" (let ((func-or-list pyim-english-input-switch-functions)) (cl-some (lambda (x) (when (functionp x) (funcall x))) (cond ((functionp func-or-list) (list func-or-list)) ((listp func-or-list) func-or-list) (t nil))))) (defun pyim-process--input-chinese-predicate-2 (event entered first-chars rest-chars) "`pyim-process-input-chinese-p' 内部函数,测试输入。" (if (not (string< "" entered)) (member event (mapcar #'identity first-chars)) (member event (mapcar #'identity rest-chars)))) (defun pyim-process-indicator-function () "Indicator function." (pyim-process--input-chinese-predicate-1)) ;; ** 解析输入 -> 获取词条 -> 自动选词 (defun pyim-process-run () "查询 entered 字符串, 显示备选词等待用户选择。" (if (pyim-process-without-entered-p) (pyim-process-terminate) (let* ((scheme (pyim-scheme-current)) entered-to-translate) (setq entered-to-translate (pyim-entered-get 'point-before)) (setq pyim-process--imobjs (pyim-imobjs-create entered-to-translate scheme)) (setq pyim-process--last-candidates pyim-process--candidates) (setq pyim-process--candidates (or (delete-dups (pyim-candidates-create pyim-process--imobjs scheme)) (list entered-to-translate))) (unless (eq (pyim-process--auto-select) 'auto-select-success) (pyim-process-plan-to-select-word 0) (pyim-process-ui-refresh) (pyim-process--run-delay))))) (defun pyim-process-without-entered-p () (= (length (pyim-process-get-entered 'point-before)) 0)) (defun pyim-process-get-entered (&optional type) (pyim-entered-get type)) (defun pyim-process-ui-hide () "隐藏 pyim 相关 UI." (run-hooks 'pyim-process-ui-hide-hook)) (defun pyim-process--auto-select () "自动上屏操作流程。 1. (:select last) 模式: 假如用户输入 \"nihao\", 然后按了 \"m\" 键, 那么当前的 entered 就 是 \"nihaom\", 如果 autoselector 返回 list: (:select last), 那么, \"nihao\" 对应的第一个候选词将上屏,m 键下一轮继续处理,这是一种 \"踩雷确认模式\". 2. (:select current) 模式: 假设用户已经输入 \"niha\", 然后按了 \"o\" 键,那么,当前 entered 就是 \"nihao\". 如果 autoselector 函数返回一个 list: (:select current), 那么就直接将 \"nihao\" 对应的第一个候选词上屏 幕。 3. 如果返回的 list 中包含 :replace-with \"xxx\" 信息,那么 \"xxx\" 上屏。" (let* ((results ;; autoselector 功能会影响手动连续选择功能,所以这里做了一些限制, ;; 只有在输入的时候才能够触发 autoselector 机制。 (when (pyim-process-self-insert-command-p this-command) (pyim-process--autoselector-results))) (select-last-word (pyim-process--autoselector-find-result results 'last)) (select-current-word (pyim-process--autoselector-find-result results 'current))) (when (or select-last-word select-current-word) (pyim-process--auto-select-word select-last-word select-current-word) ;; autoselector 机制已经触发的时候,如果发现 entered buffer 中 ;; point 后面还有未处理的输入,就将其转到下一轮处理,这种情况 ;; 很少出现,一般是型码输入法,entered 编辑的时候有可能触发。 (pyim-add-unread-command-events (pyim-entered-get 'point-after)) (when select-last-word (pyim-add-unread-command-events last-command-event)) (pyim-process-terminate) ;; 如果自动上屏操作成功完成,就返回 'auto-select-success, ;; pyim 后续操作会检测这个返回值。 'auto-select-success))) (defun pyim-process--autoselector-results () "运行所有 autoselectors, 返回结果列表。" (mapcar (lambda (x) (when (functionp x) (ignore-errors (funcall x)))) (cl-remove-duplicates pyim-process-autoselector :from-end t :test #'equal))) (defun pyim-process--autoselector-find-result (results type) "从所有 autoselector 运行结果中,寻找返回类型为 TYPE 的结果。" (cl-find-if (lambda (x) (equal (plist-get x :select) type)) results)) (defun pyim-process--auto-select-word (select-last-word select-current-word) (let ((pyim-process--candidates (pyim-process--get-autoselect-candidates select-last-word select-current-word))) (pyim-process-select-word-without-save 'do-not-terminate) (pyim-process-create-word (pyim-process-get-select-result) t))) (defun pyim-process--get-autoselect-candidates (select-last-word select-current-word) (let* ((str (plist-get (if select-last-word select-last-word select-current-word) :replace-with)) (candidates (if select-last-word (pyim-process-get-last-candidates) (pyim-process-get-candidates)))) (if (and str (stringp str)) (list str) candidates))) (defun pyim-process-get-last-candidates () pyim-process--last-candidates) (defun pyim-process-get-candidates () pyim-process--candidates) (defun pyim-process-ui-refresh (&optional hightlight-current) "刷新 pyim 相关 UI." (run-hook-with-args 'pyim-process-ui-refresh-hook hightlight-current)) (defun pyim-process--run-delay () "运行延迟获取候选词流程。 当用户输入停顿时间超过 `pyim-process--run-delay' 这个阈值时,就激 活延迟获取候选词流程,目前,延迟获取候选词有两种处理模式: 1. 同步+限时+用户抢断模式:比如:搜索 buffer 词条等。 2. 异步模式:比如:调用云输入法接口等。 注意:按理说,两种模式的延时阈值应该单独设置的,但当前 pyim 没有 将其分开,因为这样做在满足当前需求的同时,可以简化代码,如果以后 有新功能必须将其分开时,再做考虑。" (pyim-process--run-delay-timer-reset) (setq pyim-process--run-delay-timer (run-with-timer pyim-process-run-delay nil #'pyim-process--run-delay-timer-function))) (defun pyim-process--run-delay-timer-reset () "Reset `pyim-process--run-delay-timer'." (when pyim-process--run-delay-timer (cancel-timer pyim-process--run-delay-timer) (setq pyim-process--run-delay-timer nil))) (defun pyim-process--run-delay-timer-function () "Function used by `pyim-process--run-delay-timer'" (pyim-process--handle-candidates-async) (pyim-process--handle-candidates-limit-time)) (defun pyim-process--handle-candidates-limit-time () "使用限时的方式获取候选词。" (let* ((scheme (pyim-scheme-current)) (words (pyim-candidates-create-limit-time pyim-process--imobjs scheme))) (when words (setq pyim-process--candidates (pyim-process--merge-candidates words pyim-process--candidates)) (pyim-process-ui-refresh)))) (defun pyim-process--merge-candidates (new-candidates old-candidates) "将 OLD-CANDIDATES 和 NEW-CANDIDATES 合并的默认策略。" (remove nil (delete-dups `(,(car old-candidates) ,@new-candidates ,@(cdr old-candidates))))) (defun pyim-process--handle-candidates-async () "使用异步的方式获取候选词条词条。" (let ((scheme (pyim-scheme-current)) (buffer (current-buffer))) (pyim-candidates-create-async pyim-process--imobjs scheme (lambda (async-return) (with-current-buffer buffer (when (and (pyim-process--translating-p) (not (input-pending-p)) (equal (car async-return) pyim-process--imobjs)) (setq pyim-process--candidates (pyim-process--merge-candidates (cdr async-return) pyim-process--candidates)) (pyim-process-ui-refresh))))))) ;; ** 预选词条相关 (defun pyim-process-plan-to-select-word (word-position) "预选 candidates 列表中 WORD-POSITION 位置的词条。" (setq pyim-process--word-position word-position)) (defun pyim-process-plan-to-select-char-in-word (char-position) "以词定字功能中,通过 CHAR-POSITION 预选词条中的汉字。" (setq pyim-process--char-position-in-word char-position)) (defun pyim-process-next-word-position (n) "返回已选词条后面地 N 个词条对应的位置。" (let* ((new (+ (pyim-process-word-position) n)) (max (1- (pyim-process-candidates-length))) (pos (if (>= max new) (if (< new 0) max new) 0))) pos)) (defun pyim-process-word-position (&optional position) "返回已选词条的位置。" (min (- (pyim-process-candidates-length) 1) (if (integerp position) position pyim-process--word-position))) (defun pyim-process-candidates-length () "返回候选词条列表长度。" (length pyim-process--candidates)) ;; ** 选词造词相关 (defun pyim-process-select-nothing () "不选择任何东西。" (pyim-outcome-erase) (pyim-process-terminate)) (defun pyim-process-select-entered () (pyim-outcome-add (pyim-entered-get 'point-before)) (pyim-process-terminate)) (cl-defgeneric pyim-process-select-word (scheme) "按照 SCHEME 对应的规则,对预选词条进行选词操作。") (cl-defmethod pyim-process-select-word :after (_scheme) "运行 `pyim-select-finish-hook'." (run-hooks 'pyim-select-finish-hook)) (cl-defmethod pyim-process-select-word ((_scheme pyim-scheme-quanpin)) "按照全拼规则,对预选词条进行选词操作。" (pyim-process--create-code-criteria) (pyim-process-select-word-without-save 'do-not-terminate) (if (pyim-process--multi-step-select-word-p) (pyim-process--select-word-in-next-step) (pyim-process-create-word (pyim-process-get-select-result) t) (pyim-process-terminate))) (defun pyim-process--create-code-criteria () "创建 `pyim-process--code-criteria'." (setq pyim-process--code-criteria (let ((str (string-join (pyim-codes-create (pyim-process-get-first-imobj) (pyim-scheme-current))))) (if (> (length pyim-process--code-criteria) (length str)) pyim-process--code-criteria str)))) (defun pyim-process-select-word-without-save (&optional do-not-terminate) "选择词条但不保存词条。" (let ((word (nth pyim-process--word-position pyim-process--candidates))) (pyim-outcome-add (concat (pyim-outcome-get) word)) (unless do-not-terminate (pyim-process-terminate)))) (defun pyim-process--multi-step-select-word-p () "判断是否使用连续选词模式。" (and (not (pyim-process--select-char-in-word-p)) ;以词定字的时候,不连续选择,处理起来太复杂。 (or (pyim-process--entered-to-be-translated) (> (length (pyim-process-get-entered 'point-after)) 0)))) (defun pyim-process--select-char-in-word-p () pyim-process--char-position-in-word) (defun pyim-process-get-first-imobj () (car pyim-process--imobjs)) (defun pyim-process--entered-to-be-translated () "连续选择时,获取 entered 未转换的一部分. 大体来说,entered 字符串可以分解为三个部分: 1. 光标前字符串 1. 光标前已经转换的字符串 2. 光标前还没有转换的字符串。 2. 光标后字符串 对 entered 字符串的处理思路是:截取已经转换的字符串,把未转换的字 符串和光标后的字符串合并后下一轮递归的处理。 比如:entered 为 xiaolifeidao, 本次选择 “小李” 之后,需要将 entered 截断,“小李” 这个词条长度为 2, 就将 entered 从头开始缩减 2 个 imelem 对应的字符,变成 feidao, 为下一次选择 “飞” 做准备。 在连续选择时,当前选择的词条和 outcome 是不一致的,比如: xiaolifeidao 第一次选择:小李, outcome = 小李 第二次选择:飞, outcome = 小李飞 第三次选择:刀, outcome = 小李飞刀 注意事项: 这里有一个假设前提是: 一个 imelem 对应一个汉字, 在全拼输入法中,这个假设大多数情况是成立的,但在型码输入法 中,比如五笔输入法,就不成立,好在型码输入法一般不需要多次 选择。" (let* ((imobj (pyim-process-get-first-imobj)) (length-selected-word-in-this-step (length (pyim-outcome-diff)))) (when (< length-selected-word-in-this-step (length imobj)) (string-join (mapcar (lambda (w) (concat (nth 2 w) (nth 3 w))) (nthcdr length-selected-word-in-this-step imobj)))))) (defun pyim-process--select-word-in-next-step () "在连续选词模式下,下一轮需要进行的选词操作。" (let ((entered-to-be-translated (pyim-process--entered-to-be-translated))) (pyim-process-with-entered-buffer ;; 把光标前已转换的 entered 字符串, 从 entered 字符串里面去掉,保留未 ;; 转换的字符串和光标之后的字符串。 (delete-region (point-min) (point)) (insert entered-to-be-translated) ;; 为下一次选词作准备,一般情况下词库里面的词条不会超过20个汉字,所以 ;; 这里光标向前移动不超过20个 imelem. 从而让下一轮处理时的 “光标前字符 ;; 串” 比较长,这种方式可能比逐字选择更加好用。 (goto-char (pyim-process-next-imelem-position 20 t 1))) (pyim-process-run))) (defun pyim-process-create-word (word &optional prepend wordcount-handler criteria) "将中文词条 WORD 添加编码后,保存到用户选择过的词生成的缓存中。 词条 WORD 默认会追加到已有词条的后面,如果 PREPEND 设置为 t, 词条就会放到已有词条的最前面。 这是函数会调用 `pyim-cstring-to-codes' 来获取中文词条对应的编码。 WORDCOUNT-HANDLER 可以是一个数字,代表将此数字设置为 WORD 的新词频, WORDCOUNT-HANDLER 也可以是一个函数,其返回值将设置为 WORD 的新词频, 而这个函数的参数则表示 WORD 当前词频,这个功能用于:`pyim-dcache-import', 如果 WORDCOUNT-HANDLER 设置为其他, 则表示让 WORD 当前词频加1. 如果 CRITERIA 是一个字符串,在多音字矫正时,将使用这个字符串来矫 正多音字。 BUG:拼音无法有效地处理多音字。" (when (pyim-process--create-word-p word) (pyim-process--add-last-created-word word) (pyim-process--add-word-to-dcache word prepend wordcount-handler criteria))) (defun pyim-process--create-word-p (word) (and (> (length word) 0) ;; NOTE: 十二个汉字及以上的词条,加到个人词库里面用处不大,这是很主观的一 ;; 个数字,也许应该添加一个配置选项? (< (length word) 12) (not (pyim-string-match-p "\\CC" word)))) (defun pyim-process--add-last-created-word (word) (setq pyim-process--last-created-words (cons word (remove word pyim-process--last-created-words)))) (defun pyim-process--add-word-to-dcache (word prepend wordcount-handler criteria) (let* (;; PYIM 有些功能会用到 text property, 保存词条之前将 text property 去除,防 ;; 止不必要的数据进入 cache. (word (substring-no-properties word)) (scheme (pyim-scheme-current)) (code-prefix (pyim-scheme-code-prefix scheme)) (codes (pyim-cstring-to-codes word scheme (or criteria pyim-process--code-criteria)))) ;; 保存对应词条的词频 (when (> (length word) 0) (pyim-dcache-update-wordcount word (or wordcount-handler #'1+))) ;; 添加词条到个人缓存 (dolist (code codes) (unless (pyim-string-match-p "[^ a-z-]" code) (pyim-dcache-insert-word (if (and (> (length word) 1) (> (length codes) 1)) ;; 如果 word 超过一个汉字,并且得到多个 codes,那么大概率说明没有 ;; 正确处理多音字,这里设置一下 :noexport 属性,在导出词条的时候 ;; 不导出这些带标记的词。 (propertize word :noexport t) word) (concat (or code-prefix "") code) prepend))))) (defun pyim-process-get-select-result () "返回 PYIM 选择操作的结果。" (pyim-process-magic-convert (pyim-outcome-get))) (defun pyim-process-magic-convert (string) "返回 STRING 以词定字和魔术转换后的新字符串." (pyim-outcome-magic-convert (pyim-process--char-in-word string))) (defun pyim-process--char-in-word (word) (let ((pos pyim-process--char-position-in-word) (length (length word))) (if (and (integerp pos) (< pos length)) (substring word pos (1+ pos)) word))) (cl-defmethod pyim-process-select-word ((_scheme pyim-scheme-xingma)) "按照形码规则,对预选词条进行选词操作。" (pyim-process-select-word-without-save 'do-not-terminate) (if (pyim-entered-in-the-middle-of-entered-p) (progn (pyim-process-with-entered-buffer (delete-region (point-min) (point))) (pyim-process-run)) (pyim-process-create-word (pyim-process-get-select-result) t) (pyim-process-terminate))) (defun pyim-process-select-last-char () "选择上一个输入的字符。" (pyim-outcome-add (concat (pyim-outcome-get) (pyim-process-select-handle-char last-command-event))) (pyim-process-terminate)) (defun pyim-process-select-handle-char (char) "Pyim 字符转换函数,CHAR 代表 *待输入* 的字符。" (let ((str (char-to-string char))) (cond ((pyim-process--invalid-char-p char) "") ((and (pyim-outcome-trigger-p (char-to-string char)) (pyim-process-trigger-feature-run-p)) "") ((pyim-process--punctuation-half-width-p char) str) ((pyim-punctuation-p char) (pyim-punctuation-return-proper-punct char)) (t str)))) (defun pyim-process--invalid-char-p (char) "当 CHAR 是空格前面的字符时,返回 t." (< char ? )) (defun pyim-process-trigger-feature-run-p () (not (eq (pyim-process--trigger-feature-run) 'without-trigger-feature))) (defun pyim-process--trigger-feature-run () (cond ((pyim-process--trigger-delete-word-p) (let ((number-before-2 (pyim-char-before-to-number 1))) (delete-char -2) (pyim-process-delete-word-at-point number-before-2))) ((pyim-process--trigger-create-word-p) (let ((number-before-1 (pyim-char-before-to-number 0))) (delete-char -1) (pyim-process-create-word-at-point number-before-1))) ((pyim-process--trigger-call-function-p) (pyim-outcome-call-trigger-function)) ((pyim-process--trigger-punctuation-to-full-width-p) (pyim-punctuation-translate 'full-width)) ((pyim-process--trigger-punctuation-to-half-width-p) (pyim-punctuation-translate 'half-width)) (t 'without-trigger-feature))) (defun pyim-process--trigger-delete-word-p () "当光标之前的字符串类似 “<中文>[1-9]-” 时,比如 “你好2-” ,返回 t." (let* ((str-before-2 (pyim-char-before-to-string 1)) (str-before-3 (pyim-char-before-to-string 2))) (and (eq (char-before) ?-) (pyim-string-match-p "[0-9]" str-before-2) (pyim-string-match-p "\\cc" str-before-3)))) (defun pyim-process-delete-word-at-point (&optional number silent) "将光标前字符数为 NUMBER 的中文字符串从个人词库中删除 当 SILENT 设置为 t 是,不显示提醒信息。" (let ((string (pyim-cstring-at-point (or number 2)))) (when string (pyim-process-delete-word string) (unless silent (message "词条: \"%s\" 已经从个人词库缓冲中删除。" string))))) (defun pyim-process--trigger-create-word-p () "当光标之前的字符串类似 “<中文>[2-9]” 时,比如 “你好2” ,返回 t." (let ((str-before-2 (pyim-char-before-to-string 1))) (and (member (char-before) (number-sequence ?2 ?9)) (pyim-string-match-p "\\cc" str-before-2)))) (defun pyim-process-create-word-at-point (&optional number silent) "将光标前字符数为 NUMBER 的中文字符串添加到个人词库中,当 SILENT 设置为 t 是,不显示提醒信息。" (when-let* ((string (pyim-cstring-at-point (or number 2)))) (pyim-process-create-word string) (unless silent (message "PYIM: 将词条 %S 加入词库。" string)))) (defun pyim-process--trigger-call-function-p () "当光标之前是中文但不是标点符号时,返回 t." (let ((str-before-1 (pyim-char-before-to-string 0))) (and (not (pyim-punctuation-position str-before-1)) (pyim-string-match-p "\\cc" str-before-1) (functionp pyim-outcome-trigger-function)))) (defun pyim-process--trigger-punctuation-to-full-width-p () "当光标前面是半角标点时,返回 t." (let* ((str-before-1 (pyim-char-before-to-string 0)) (punc-posit-before-1 (pyim-punctuation-position str-before-1))) (and (numberp punc-posit-before-1) (= punc-posit-before-1 0)))) (defun pyim-process--trigger-punctuation-to-half-width-p () "当光标前面是全角标点时,返回 t." (let* ((str-before-1 (pyim-char-before-to-string 0)) (punc-posit-before-1 (pyim-punctuation-position str-before-1))) (and (numberp punc-posit-before-1) (> punc-posit-before-1 0)))) (defun pyim-process--punctuation-half-width-p (char) "根据 CHAR 和环境信息,判断是否输入半角符号。" (or (not (pyim-process--punctuation-full-width-p)) (pyim-punctuation-auto-half-width-p char) (pyim-punctuation-escape-p (char-before)))) (defun pyim-process--punctuation-full-width-p () "判断是否需要切换到全角标点输入模式 输入标点的样式的改变(全角或者半角)受三个方面影响: 1. 用户是否手动切换了标点样式? 2 用户是否手动切换到英文输入模式? 3. pyim 是否根据环境自动切换到英文输入模式? 三方面的综合结果为: 只要当前的输入模式是英文输入模式,那么输入的 标点符号 *必定* 是半角标点,如果当前输入模式是中文输入模式,那么, 输入标点的样式用户可以使用 `pyim-punctuation-toggle'手动控制,具 体请参考 `pyim-process--punctuation-full-width-p'。" (cl-case (car pyim-punctuation-translate-p) (yes t) (no nil) (auto ;; 如果用户手动或者根据环境自动切换为英文输入模式, ;; 那么标点符号也要切换为半角模式。 (and (not pyim-process--input-ascii) (not (pyim-process-auto-switch-english-input-p)))))) (defun pyim-process-select-word-and-last-char () "选择预选词条和上一次输入的字符。" (let ((word (nth (1- pyim-process--word-position) pyim-process--candidates))) (pyim-outcome-add (concat (pyim-outcome-get) word (pyim-process-select-handle-char last-command-event))) (pyim-process-terminate))) ;; ** 删词相关 (defun pyim-process-delete-word (word) (pyim-dcache-delete-word word) (pyim-process-remove-last-created-word word)) (defun pyim-process-remove-last-created-word (word) (setq pyim-process--last-created-words (remove word pyim-process--last-created-words))) (defun pyim-process-last-created-word () (car pyim-process--last-created-words)) (defun pyim-process-last-created-words () pyim-process--last-created-words) ;; * Footer (provide 'pyim-process) ;;; pyim-process.el ends here pyim-5.3.3/pyim-cloudim.el0000644000175000017500000000774314353263012015276 0ustar dogslegdogsleg;;; pyim-cloudim.el --- cloud input method support for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'url) (require 'pyim-candidates) (defgroup pyim-cloudim nil "Cloud input method for pyim." :group 'pyim) (defcustom pyim-cloudim nil "设置 pyim 使用的云输入法。" :type '(choice (const :tag "Do not use cloud input method." nil) (const :tag "Use baidu cloud input method." baidu) (const :tag "Use google cloud input method." google))) (cl-defmethod pyim-candidates-create-async (imobjs (scheme pyim-scheme-quanpin) callback &context (pyim-cloudim (eql baidu))) "按照 SCHEME, 使用异步的方式从 IMOBJS 获得候选词条,用于全拼输入法。 这里使用 baidu 提供的云输入法接口获取词条。" (let ((str (string-join (pyim-codes-create (car imobjs) scheme)))) (unless (< (length str) 1) (url-retrieve (format "https://olime.baidu.com/py?py=%s" str) (lambda (_) (funcall callback (cons imobjs (pyim-cloudim--parse-baidu-buffer))) (kill-buffer)) nil t)))) (defun pyim-cloudim--parse-baidu-buffer () "解析 `pyim-cloudim-url-retrieve-sync' 返回的 baidu buffer." ;; NOTE: 以前这个函数使用 `json-parse-buffer' 来处理返回的结果,但因为旧版本 ;; Emacs 没有 `json-parse-buffer' 函数,所以现在改用这种简单粗暴的方式,虽然没 ;; 有使用 json 得到的结果精确,但应该适用于大多数情况,同时也减少了一个包依赖。 (let ((words (pyim-cloudim--parse-baidu-buffer-string (buffer-string)))) (when (> (length words) 0) (mapcar (lambda (word) (propertize word :comment "(云)")) words)))) (defun pyim-cloudim--parse-baidu-buffer-string (string) "从 baidu buffer STRING 中抓取中文词条,返回对应的词条列表." (let ((string (decode-coding-string string 'utf-8)) (sep "丨")) (cl-remove-if-not (lambda (x) (> (length x) 0)) (split-string (replace-regexp-in-string "\\CC" "" (replace-regexp-in-string "," sep string)) (format "[%s]+" sep))))) (cl-defmethod pyim-candidates-create-async (imobjs (scheme pyim-scheme-quanpin) callback &context (pyim-cloudim (eql google))) "按照 SCHEME, 使用异步的方式从 IMOBJS 获得候选词条,用于全拼输入法。 这里使用 google 提供的云输入法接口获取词条。" (let ((str (string-join (pyim-codes-create (car imobjs) scheme)))) (unless (< (length str) 1) (url-retrieve (format "https://www.google.cn/inputtools/request?ime=pinyin&text=%s" str) (lambda (_) (funcall callback (cons imobjs (pyim-cloudim--parse-google-buffer))) (kill-buffer)) nil t)))) (defun pyim-cloudim--parse-google-buffer () "解析 `pyim-cloudim-url-retrieve-sync' 返回的 google buffer." (pyim-cloudim--parse-baidu-buffer)) ;; * Footer (provide 'pyim-cloudim) ;;; pyim-cloudim.el ends here pyim-5.3.3/pyim-pymap-utils.el0000644000175000017500000007562214361471235016136 0ustar dogslegdogsleg;;; pyim-pymap-utils.el --- Utils used to develop pyim-pymap.el file -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2015-2020 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;; * 说明文档 :doc: ;; 这个文件中包含工具函数 `pyim-pymap-build-pymap',用于更新 pyim-pymap.el 中 ;; `pyim-pymap' 的定义,它使用 libpinyin 项目的 data 文件。 ;; 1. [[https://github.com/libpinyin/libpinyin/releases/download/2.6.0/libpinyin-2.6.0.tar.gz][libpinyin-2.6.0.tar.gz]] ;;; Code: ;; * 代码 :code: (require 'pyim-common) (require 'pyim-pymap) ;; 如果改变这个变量的取值,那么 pyim-tests.el 中,许多 tests 都可能需要更新。 (defvar pyim-pymap--commonly-used-cchar (cl-remove-if-not (lambda (char) (string-match-p "\\cc" char)) (split-string " 的一国在人了有中是年和大业不为发会工经上地市要个产这出行作生家以 成到日民来我部对进多全建他公开们场展时理新方主企资实学报制政济用 同于法高长现本月定化加动合品重关机分力自外者区能设后就等体下万元 社过前面农也得与说之员而务利电文事可种总改三各好金第司其从平代当 天水提商十管内小技位目起海所立已通入量子问度北保心还科委都术使明 着次将增基名向门应里美由规今题记点计去强两些表系办教正条最达特革 收二期并程厂如道际及西口京华任调性导组东路活广意比投决交统党南安 此领结营项情解议义山先车然价放世间因共院步物界集把持无但城相书村 求治取原处府研质信四运县军件育局干队团又造形级标联专少费效据手施 权江近深更认果格几看没职服台式益想数单样只被亿老受优常销志战流很 接乡头给至难观指创证织论别五协变风批见究支那查张精林每转划准做需 传争税构具百或才积势举必型易视快李参回引镇首推思完消值该走装众责 备州供包副极整确知贸己环话反身选亚么带采王策真女谈严斯况色打德告 仅它气料神率识劳境源青护列兴许户马港则节款拉直案股光较河花根布线 土克再群医清速律她族历非感占续师何影功负验望财类货约艺售连纪按讯 史示象养获石食抓富模始住赛客越闻央席坚份士热限米银息校均房周游千 失八检足配存九命尔即防钱评复考依断范础油照段落访未额双让切须儿便 空往你层低奖注黄英承远版维算破铁乐边初满病响药助致善突爱容香称购 届余素请白宣健牌促培竞巴稳继紧字困刘旅声超随例担友号显却监材且春 居适除红半买充陈火搞图阳六察试太什执片古七球修尽控讲排粮武预亲挥 卖审措荣洲卫希店良属险曾围域令站苏龙念罗吨器汇康减习演普田班待星 飞写矿轻扩言章汽靠毛终仍景置底福止离泽波兰核降训逐票菜座献钢眼损 宁像苦印融独湖早予夫编换欧努著顾征升态套介送某斗状画留航派室临兵 补宝略黑综云差纳密贫剧犯阿击遇岁阶烈督吃丰馆招害官树听庭另沙私针 胜贷网愿托缺园假酒音巨既判输讨测读洋括筑欢刚庆久陆找楼激晚绝压故 互签汉草木亩短绍迎吸警藏疗贵纷授登探索湾宏录申诉秀序顺死卡歌午孩 桥喜川邓扬津温船库订练候退违否彩棉帮拿罪币角召灾妇杨奋绩虽煤免笔 够永圳停奥鲜朝吴岛觉移尼急博贯拥束左细舞幅语俄奇般简拍脑债固威券 追筹刻映繁伟甚饭右彻烟沿街血冲洪植誉刊玉厅救潮迅伍怎付倍顿述播励 斤乎纸振旧障鼓艰呼吉男绿尚夏亏季松哈祖典韩遍夜轮板抗摄杂皮贡借幕 罚伤岸扶乱曲脱践危澳童散味叶累谢孙邮雄兼微呢谁惠偿署择染答块徐鱼 赞课盛延瑞怀堂驻零辆齐胡途封似润守毕坦母雨败朱污趋械纺租灵拓残含 握跨衣储瓦蒙鉴析竟骨档秘禁赵宾异伊智钟键辉跃冷倒庄毒仪哪涉泛宗鹏 归岗雷礼尤休泰疾肥珠叫牛宜抵挂寻父攻佳塞架符裁虑肉启丽露鲁秋昌估 射册若宽厚盾硬末轨饮勤茶诗郑冠涨篇泥唱纯坡熟浙晓抢丝锦载笑勇杰患 乌坐雪戏背塔翻沈遗聚渠哥享迹森辽衡掌牧附操赶览野盟殊仁错萨夺梅误 词董潜卷矛腐亮冒盖旗井凡震峰坏倾距壮惊盘梁摆径忠冰峡丹避珍乘刑扎 透迫箱莫跑穿祝乏厦渐软询折浪朋敢诚弱疑邀沉端床络疆缩脚甘贴勒荒唐 静缓侵句尊塑肃怕耕痛援劣伙挑洗暴冬龄乔餐肯廉跟阵伐悉忘闭奔恢宋泉 杯渡吗奉婚赴恩盐掉洁亡洛聘蔬混摩抽鸡剂胆麦谋雅废贺羊阔唯捐返隆穷 辛猪帐饰郭颁灯绕诸伴顶祥谓恶番敏旦劲缴麻屋跳码鞋扣迈忙趣盈棋勃敬 辑摊旺纠炼梦偏渔牙侨黎赔裕宫谷概稿柱弹殖秩凭拨幸洞伪沟姓遭涌陶迁 诺拔畅忧胞丁蓄贝舍腾杀煌圆伦横薄畜毫豪弟呈佛邦您墨徽惯循蓝烧触陕 拖伯盲宪净卢炭籍秦粉妻爆欣释玩俊欠蛋猛迪苗暂貌遵锡楚桂昆杜皇醒燃 凤截铺液撤胶慢杭虚辞曼毅咨俗糖忽芳姐耗妈谊浦频阻允宅窗默胀弃倡灭 甲症埃滨赏莱拒淡坛陵绘虎竹赢锋篮迷纽轿贩递娘圈挖炉替幼乃郊颇戴滑 徒崇涛焦凝墙吧炎刀玻寿履圣昨酸朗媒桑铜仲亦诞揭纵漫愈辟赠旱奶泳枪 骗虫池镜浓拆艾扫娱钻碍寒迟邻曹盗穆豆赚晨浩彭耳瓜扭脸燕摇寄仿炮晋 泪欲饱壁锁刷柬诊磨捕寨滚膨孔添帝辖炸旨吁址驶抱嘉拜扰袋佩阴辈锅赖 剩押怪浮枚栏毁柳恐敦孟旁仓岩伸岭耐懂捷璃溪暖纤汗疫巧旋侧冶陪鸣瓶 纲挤旬舆喝陷缘稻饲滩隔慰朴隐灌拟偷闲赫恰慧蒋闹邹牵柴刺滞彰俱勘填 琛尝贾搬淮奏荷滋覆役秒踏巩摸荡辅惜柜肖颗搏氏姑弄姜君舒兑宇割哲摘 钦逃漠忆敌宿啊凌耀闯阅贪赤汪悲抑瓷冯厉粗菲琴堡斌掘稀衰驾雕牢氛驱 妥悄郎巡臣羽灰癌颖姆漏袭贤鸟暗茂孤惩榜袁桌卓傅剑堆兆狠轰拳妹绒裂 潘兄洽叹涵贿侯岚熊绪阁尾碑尖腿涂栽坝犹铸肩闪诱辩芬睡奠伏妙乙绸廷 夕恒梯赁霞攀枝译描湘磁吕硕爸肝峻葡衷搭唤薪挺逝狗蔡宴蓬撞铝牲舰胁 崛桃斜丧烂屏砖墓详逾函跌抚插戈凉啤脉滥赋柏堤腰泊寺尘蒂削仙踪冻汤 睛艳荐劫框廊惑页拼堪携丈乳挪谱舶埔遥菌塘氧晶洒株颜虹岳胸忍甜匹瞩 懈爷丛莲叙鸿逢抬嘴弘炒喷吊窝衔吹霸仔垦胎慎脏歧疏悠慕漂杆萍舟吐玲 凯戒盼偶盆慨弊箭茅衫罐串辐腹钩碰昂酬晰姿彼锻飘嫁竣缝蹈悬紫浅缆喊 昔驰湿剪侦坑姚魏扑挣焕皆狂泡骤堵膜禽锐芝帽擅沪晤婆埋劝碗玛顷鸭娃 豫匆魂哭庞亭屡逼尺撒鹿讼弥坊碎缔霍壤萄铃稍丘肿烦苹庙雇汛孝辰吞汰 怨酿耶咱欺丢琼棚披渴屈弗疲帕昭盒仰萧牺撑抛鼠纱翼兹骑糊契铭淘顽撰 乒淑妆窑柔姻苍谨卿灿栋敲窃菊郁催眉邱揽鼎韦肤娜俏呀拚寸爬悟尿罢圭 葬聪沃肠厕慈恋绵橡圾垃翁粤脂歹憾阐甸巷蜂轴艘垄衬阜惨冀幽厘崭筋寓 迄渗碘碧赌袖奈崔悦捞剥孕逆婴脆缅艇谭笼儒粒诈遣垂磋卸帜枣幢淀帆蛇 宰殿猎叔夹帅沧魅俩牟钓葛罕渤汕溢擦袱嫩桶殷酷呆卧暑骄幻囊掀醉牡饼 扇蒸赣俭椅枢彦樊吾仗彬砂绳巾喀勋愁碱谦壳轧潭浆挽邢啥焊钞烤廖猫狱 腔喻御蕴坎魔刮瘤茫竭莉链淫愤纹咸睐睹裤夸滴雾搜拘龚凶茨傲鞍鹤蚀颈 翠卉汁冈狮隧弯胃沛募琳疼蚕泼磷捧炳绣朵涯掏奎聂孜韵浑翔魄掩斥敞腊 愧粘丑溉斑啦柯谐烯禄浴涝鬼薛瘦挡昏鹅湛逻虾沂辱叉鼻厨鲍鞭辣潇乓肺 尹颂邵澜桐鹰妨闽屠畏翰塌亟寂赂犬聊暨垫泄漆旭蕾坪涤挫佐瞄拦硫棒杏 爽碳畔熙襄祸乾淹臂莎辜阎庸砍捉勾垒衍坤噪毯倪扮铅遏哀愉瑶咬嫌闸恳 齿杠怒兽浇肇鄂溶哄棵盯梨灶屯狭陋啡浸淋濒脊戚勉膏氨墅沸挨蔓抄芒秉 刹饶厢咖魁骚缚遂恨跻螺辨菇帷凰椒汝瞬淄舱馈桩炬誓卜麟岂兔眠泵拐肚 匪芦匈霉蜜荆雁窄秧枯仆嘱壶谅哨肌贬叠稽岐沫肆醇菱彪躺摔膀甫逊凑渊 喂藤砸悔杉霜厄忌桔筒丙臭拾芜禹丸蟹嘛俞翅尸澄骂睦馨郝贮陌钧轩赃笋 歉逸歪巍萃崖窟踢锣萎庐剖籽甩饥苑恼渣痕莞硅晴巢瘫缠隶筛穴昼埠宠肢 饿仑逮兢趟糕妮邪抹俑萌匠扔酱葱礁掺雀髓悼挚蔚枫庚伞侃僵捆蒜溜傻蔗 谜斋蝶沾闷驳耿槽黔吓肾芽栗朽荫榆皖曰徊奴迭僻蓉靖氟滔羡愚尧俺徘罩 磊镑舌曙纶粪匙钉佼扯踊躲猴纬咽酝挠宛瑰歇抒茧穗祭鑫趁痴裙猜耘碌锈 晒潍弦稼狼拢梧芯眷哑宙厌逛谴邯呵蜡寥钥耸媳熏蚁惕颠娟亨吟蒲梭瞻渝 喉遮慌夷韶焰尉珊胖蕉粹裹琦秽侠奸挝绑曝棍婉镶熬傍燥氯骆晃鸽疯琢聋 瑟暇绥禅溃腺垮阀撼煮佣滕淤蹲栖硝睁荟荧抖坟芭臻锭晖倦倘喘邑锤惧荔 毗觅矮恭钙氮缸瞧颤萝佑怡瘾寡烹摧棠缪雏韧喇兜坯坷贞仇缉帘竖糟猖懒 凿洼喧谣驼烫锌椰崩沥汾磅霖棘扛彗矩瞒陇绎诫斐卵铮钾宵簿秤畴斧擂剔 躁冤讳寅焚漳鳖哺耻僧琅粟怖咏蜀淳柑缕烁氢蔽琪泣阮镀殴虞虐炊搁诀掠 坠屿髦酋躯吵遐寞仕稚僚楠矶筝彝叮熔槐潢芹郸匾咋玄裔陡哗怜襟刃脾嵌 拱慷痪跋孚峪钊滇苟晕墩膝羞乍腻詹讶敷肴莹衢柿朔袜枕烘匀歼泻樱吻翟 堰苯隙娇獗汲蛙斩靡沁乞姨翩沼嘎畸矫骏薯绚窜藻矗皂楷腕篷徇耽娼犁榻 茄棕汹峨蹄昧奢涩灼踩粥拣旷簇溯攒沓呕梳搅砌纫渭澡撕漓葆辍肪祁鞠蛮 捏诵娣岱瀑啸裸鸦瑛躬舜忱豹纂恤惟赐俯犀媚嫂嗓蚊茬驭缀皱凳钮蚂姬扒 嫖跪凹揣尬沦尴豁玫殡淌叭唇啃裘卑琐矢拯忡勿盎茵椎脖拂骅葫迢薇龟绞 眶沐傣浊舅叛浚窘栓酶笛泌榄惹铲碟捡恪酯滤匿酵砚贼匮熠鳞麓镁氓苇廓 巫踵竿蘑翘梓贻鳗帼冉泓狐涟崎窍瑜讽逗铎掷璀泗浏陲醋苛攘璧瀚哩暮矣 蚌悖扼漯烛蝴屑墟俘侣庇陀煎秸弓捣譬炜炯拌扁彤锚禾侮秆绮嚣樟咐枉窦 桦寇哉狸耍馒驹隋冕疮咄妄峙娄溥腑钠栩糙滦呐鲻娶祺刨褒橙茹谎抉慑媛 橄戎迩雯璨雍惶扳桢霓账梗炕裴韬杖痹缤沽燎煞删辙爵缭劈烨槌媲凛莆颅 锯膳澎坞瓣婷絮酌涡唁秃禺膊棣芸忻炽榨篆憨戍圩爹蹊饪胺贱睫蝇惫拇赈 泾盏弧剿硒毓皓菏灸湄炙祠荻捍嚼朦屹紊藜驴寝兮隘祈榕臧蝉绢瞎闵鳌娥 藉娅烽楂摒凄凸熄孵叩渎胳匡袍卒怠桓莽倩泸藕陨辗骋峭冥饺亢圃颐擒铵 鳄簧愣璜钰拙瘠靳隽罹岑镭榴恕毋囤汀绽窖筷擎猿诲碾夭筐邃藩诬芙胚哇 垣胧帖殉毙壑绰憋亥涅屁璞缮侍倚稠棺棱葵诣笨橱寰郡垢徕眺胰谆窥霄栉 舸蹦坂瞪珲釉跤挟侄肘嘲刁缎嚷痒敛祛绅孰痫闺椿噶恍伶峦酥萦苎癫涪锲 蜚拎嵩昊娴涣烙璋笃囚祯篱讴舷纭锄巅卦摹眸柄踞焉辄褚褐湃夙堕岔惦疚 谍奕羚帧澈濮捎漾吼锰趴菩簸仃渲札谙咕桨咀郴咳呜蛟拧莘驯庵弼逞蹬姥 撂镍晏疡爪骥楞钳懋寐淇琉杞菠铨翌靶侗瑙馅丐痊娓侈苓聆睿偌釜噬曦燮 哟瑾瞿璇拮憬鹊勺憧嗜啼檐柚呱渍镌妃溺鸥粕沱榭隅毡禧瞅鲸淆阪茁渺瞥 茜瘟礴伺谛锹蔼虔莺迸磕赡泱栈甄镐抠嬉诿甬绊饵谬梢颍揪琶褥佟腥辊溅 琵鄯拴喃笙酰粱卤芮膛斓潼鸵侥讷婿吆羁嗣蜒栅疙拷戳镛芷钛蜿铀夯摞雌 酣荼蝎锥姊瓢祀玺弛犷哦茸鱿绷茎惋亘珑莓掂迥鲤殃瘩叨螃奄腈疟沭钨昕 膺涿糠氰揉狩檀悍缫哮衙瑚潞谤搀洱涓袤痰乖冗芋甭骸幌涮俨敖槛狄牒恺 雹赎庶熨蛛佰蓦鄱煽腌黯疤倔剌斡诽锵筱妍掖铿脐捅弈邸湟眯赦拄啪玮轶 蛾麋炫赊靴箔菁撬裳戌缨蝗撇奚瀛噩怯蓓匕咚瞰佬泞扉皋晾麒姗跚瘀鄙猕 拭鲟祷脯砺驿陛瘁搓舵汞哼胫珀邬磺馏馍铢诧涧吏苔潺邳烷囿斟滁殆酚狡 孺恬沅铬湍啧囱蒿鹃柠漱胥妖洙珂茉蹒圻鬓搂葩佘渥诙袒捂瞠妓铐澧袂馁 汐匣逍谚窒蔑糯汶壹岖盔嘘迂嘀锢讥吭抨屎獭褪咫稷迦檬塬蠢蓟咎皿驮俐 坍惭垛鹭鸾蹴撩诠恙臃遨睬踌浒搪郧竺翡宦冽憩萱拽卞槟躇蘸肋呛濡酮眨 撮矸垸蛀黛涸脓徙撷曳峥渚镖钴骊袅磐掣沌埂嘿琏楣豚诡悸麝煦矾羲唉溧 呻覃兖吱惰羹钝枸姣颓铣梆骇淅孢叱谧泯谟恃薹筵鏖栾鹜哽掬辘茗瓯绛筠 铤袄殚梵挎遴榈蜕癣垠厮幄偕焱攥裨炖旮旯蔺骡娩伫猝窿虏屉缜咒筏骼璐 剃涕猗淼侬阙嗅鸳嘈霏珩沮捺硼荃驷漩嘻眩掰伽脍婪煜鹄壕崂翎痞兀婺鸯 楹咤徜嫉篓烃铂咪掐匝杼蕃箍荤砾嘶皑宕荪哎汴貂邡淦蕙弩堑惬偃徉箴赘 啻凋穹酗憎芥唾闫晔苞昶甙笺吝蕊鳝衅猩薰昱趾淞坳怅翱汩琥岌阑粼羌霆 篡塾酉裱韭唠廿闰攸黝蛤厥荞瑕柘祚疵愕蕨牦飨疹嗷癖芪漕隍徨逵泠嵘嗡 岫岷擞陂颊咔卯婶椭惘歙幺臆叽缰睽勐暄弋痔秭煲琮嘟犊玖怦丕溴罂瓮丞 惮癜晦攫镰镯柞舫铆蹼妩熹铱褂丫笆妒噢噙琬冼荀蟾捶嗒町嫣肮皎旖恣钚 砥吩茯馥钎甥嗦蜗浔谒辫亳彷珏咯淖妊佤玷嘹崴於辕贲扈伎旎孽耙娠戊冢 跷砷焘羔圪耄钼悻荥唑稞邝莅杷醛嗽唆拗碴馋胱琨茏糜懦骞蜘嚓怵抡唢腆 涎灏臼墒暹椽牍钒猾榔懵枇樵锶籼箫漪帚钵赓捻郅儋烬锂剽锑鄢鄞臾喳胄 耋阱笠瓴啬杳萤莠嶂浜傩遒轼睢倜矽仉唬旌酪腼罄嬗畲祟桅悴讹憔龋嵊绶 邕忖箩咆晌愫猷帛麾莒觑吮蟋庥懊阂蒯阡腮潸晟蟀臀罔骁崽绉粽忿肛蠡遛 蜓煊蚜坻滹銮悯鼐撵噼忐湮侏粳矍铄坨铉盂锗阖溟俟忑赝鬃敝宸哆靓揩瘸 鲅篝氦嚎浃缙飚锷癸柩蛎濂榷鲨钡盹鲫诘诩迤桎遁尕梏楫赳飒锃雉怆痼劾 痢喽霹昙畹胭佚狈瘪姹吠铧谏雳咙畦荠娑褶忏惚痉橘漉诏呗晁惆砀馄戟峁 昵拈蠕虱洵鹦蛹铛挛倏澍濉钅噜咛俳磬蜷霎肽砼聿怔砭谌箕蹶孪蔷糅挞饨 惴禀淙哒枷楝闾蜻嗖淬垩矜郗蚤嫦喋镉饯髋潦镂簌偎鹉岙踱诃籁宓膘飙涞 耆荏渑豌琰俎绌埭幡赅锆崮碣珞腋滢蓖伉馗聩幔锨蓥鹑砝酩枰鞘苋粑蹭倌 犟俪嶙砻嵋滂葺苒枭翊婀飓阚喟傈藐蜃怂稣亵诒蜇岜霁瞌沏卅舀鹌俸嵇蟒 汨砰鞣唏陉佯恿竽瘴祉焙诋濠螂叻垅谩朐稔芍瞳惺萸盅啄眈偻爿蟠炔垭噎 蛰擘锏茭悌喔谑峋妪恽韫褓镳饽杈戛鸠萋襁榫霭苄跺杲嗨珉哌娆孀恸缄夔 佗饷苷郜鼾颌訇谲溘咧褛逄颦洮逶嫡蠹碓烩醴栎鎏瓤伢蔫怿甾摈畈镣螨秣 搔盱痍搐蹉佃绂疽骝霾悚缃懿咂奘轱邗蚝瘘醚湎瞑掮羟仨砣郢砧鳟跛踝轲 窠郦踉躏戮篾骐鳍蹂郯跎倭诅鄄褴阆缈嗯妞沤跄箐苕窕楔饴峄腴圄谕揍踹 罡佝颔觊篑鲢綦妾镗啕蚬窈揖眙蟑诛钗绯讣睾媾嗬祜镢囹苜坭蛐髯搡叟蹋 觎捱碉呋罘荚鹫岿寮扪焖狞鳅嗄嗤擀痂嗟颉蚧儆锴龛嗑锟俚枥懑讫橇嗪虬 跆骧陟灞恻涔酐鸪牯钜萘鲶缥曜蚓诤埕墀麸蝠蛊遑厩趄沔耦疱匍揿蚯讪唰 舔呷蓿鹧膑刍耷鞑裆趸孑鲲绫埝嘭舢鸢螯吡蝙疸匐桁铠羸鲈囵唛仫庖劭郓 骜粲峒腓鹳鳜蚶囫茴峤蟆蘖癯纾僳皙隰缬馐谪捭汊碜塍艮睑狍苫篦蜍锉沣 诰晗喙麂謇蹇觐啾踽邈壬燧娲猥歆镒茔昝赭狰孳哧舛噔鹗蚣逅洹腱锒纰蛆 蕤姝邰纣嘣钹衩婵孱蹿鲷萼椁浣镓遽赉趔蕲剜邂仡氤獐幛俾铋嗔茌氡诂豢 桧畿倥捋仞忒疃浯蜈榛偬稗菖鲳厝踮叼痱貉玑婕琚疴掳钤垧氵黠跹怏揄氲 铡濯芾笈崆钕菽隼傥仝囗芗埙簪暧桉镝蚪蜉藁笳菅龃喹橹抿啮蹑逖唔樨巽 揶黟訾钣嵯凼恫掇剁珙沆噱揆耒铌泅疝葳隗滟龉钺殒蒡觇黜澹酊垡奂珈濑 馕馊嚏痿岘氩茱滓焯抻豉敕掸碲靛摁淝鳏盥皈鲑颢犄翦铰椐胯屺邛庹猬蓊 骛浠桠胤鸩痣蛭噌杵啜靼啶煅枋觥毂刽蝈蘅芨戬醮疖忾骷洌呤荦觞谡瀣蝣 糌倬碚蹙痘砘绀虢蕻肓蛔唧桀蝌侩棂樯挈轫巳崧蓑藓鳕瑗帙馔豺痤郇殓髅 轳逯嗫戕嚅蛳琊嘤疣蚱钯钿碇咣毽迳喱逦廪邙囡匏扦亻咝凇纨涠庠溆醺炀 烊肄龈谀锱瘢枞皴贰晷闳斛屐讦婧苣蔻绺渌瑁螟叵颀穑膻羧螳绦誊蜥楦恂 靥咿翳瓒枳啭樽嫒婊搽铒跗凫菡篁髻裾栲癞蓼氖孬喏砒姘衽缛嵬挹缢慵呦 箸蹩槎榇舂嗲胴谔岢圹娌潋蛉酃鲵鲇娉亓碛芊忪谇笤韪勰呓俣圜愠仄炷毖 筚伧棰磴滏篙肱笕堇馑荩榘哐傀崃罱痨儡鹂檩垴仵檄芎阉刈壅馀庾妯躅獒 阊笞饬钏硐椴泔硌鹘鳇豇狙戡莨啉辇臬殇舐黍薮眭佻嗵煨莴蚴妤瘐擢蛏蹰 龊辏绐氘骶莪珐缟聒讧岬胛桷谰戾撸鸬雒嘧囔铍骈掊茕噻铯柁艉龌硖罅魇 酽咦嶷羿轸趵荸薜踟玳啖蔸槁鲛疥砬唳弭曩黏镊泮霈淠柒颧瘙痧辋郄燹泫 郾鹞钇殪痈甑踯翥婢檗柽啐菪嶝腭嗝剐笏蟥戢阄噘撅尻贶辚蜢颞忸胼阕竦 焐揠邺鳙啁稹徵诌隹舨哔卟伥苌鹚箪缍锇蝮诟洄浍诨犍硷噤垲郐椤嫫伲脲 殍噗溱箬厍钽钍恹鬻爰砦蓁胝颛褙鳊邴铖镫腚钭颚鲂悱狒佶偈堀绔醪坜疠 椋犸暝佞哝瞟荨芩逡溽裟挲抟暾崦芫荑薏莸欤栀斫镞嗳鸨跸骠俦谠簟棼驸 掼倨橛犒邋耧蝼虻铙郫汔诮楸阒绻叁臊钐腧闩菘阗忝橐翕阋踅窨鹬鼋樾錾 吒旃弁侪坼蚩嘬糍骢氐呃榧玢绋蚨钆岣菰罟嘏埚绗嚯藿笄袈羯肼暌啷蒗蜊 獠鬣熳黾乜镆怩驽旆髂仟芡谯恁鳃艄莳艏趿遢鲐醍僮氽刎芴喑墉昀箦鄣摺 钲贽缵鏊锛瓿廛瘳亍遄褡垌椟酆砩桴赙坩臌曷跽湫榉黧猁钌镏缦殁赧埤悭 缱衾鲭铩猞眚铈谥耜飕饕餮骰乇绾鹇鲞爻蜴镱铟莜祗濞镔逋谄谶酲茺樗憷 莼撺柢阏砜垓旰妫衮嗥郏鞯徼孓钪侉夼跬铼嫘蟊茆睨怄蹁谝嘌綮嫱筇犰穰 铷筲哂炻豕秫笥涑铊帏闱鋈舾屣狎哓噫璎铕宥阈豸辎趑龇捌秕荜愎窆镲谗 踔苁酢呔聃镦屙鲱鬲膈铪醐獾鲩虺葭牮礓苴讵颏裉诳栌氇镙哞柰袢帔睥苤 嫔笸氆佥箧跫蚋鲥扌狲桫溏铽殄脘洧肟绡咻洫癔洇嵛磔胗肫赀眦吖瑷埯畚 妣飑豳髌砗铳楮蔟毳锝堞疔葑缶菔疳彀胍磙顸薅翮猢怙蒺廑妗髁醌粝魉旒 蝥缗衲呸醅芘蚍圮榀萁苘逑诎劬蕖朊剡蟮椹饣酞帑葶菟魍庑葸氙谖鞅狺夤 嬴瘿饔雩鹆橼赜潴骓缁诹怍杓艹檫媸氚呲殂矬笪迨纛簦玎苊轭匚鼢呒缑诖 炅鲧唿戽鬟恚袷瘕枧洚桕雎蠲剀诓瘌镧铑鳓蓠呖跞裢裣埒捩鲮熘嵝瘰镘脒 腩筢耪辔牝嘁蛴戗蛩巯悫葚熵绱蛸螫毹妁纟嗾鳎绨粜菀沩鼯牾螅顼泶蕈鼹 繇苡悒廴吲喁卣牖笮舴罾棹鸷碡锕嗌媪龅甏箅傧啵鹁晡氅魑篪怛籴礅蒽珥 钫绠觚鸹涫颃篌锪蠖乩咭赍嵴铗湔槿赆僦皲佧箜蒉缧酹嘞疬臁膦泷蒌泺荬 颟旄泖镅蠓冖幂耱襻鼙攵炝愀蘧氍犭禳桡糁馓酾槊狻锬羰鼗鹈畋髫萜堍璺 怃崤囟睚痖菸餍徭瘗唷圉蜮砟谵澶朕摭轵诼笫廒聱庳髀笾龀裎雠蝽腠妲刂 铥黩怼沲蘩趺苻拊阝鲋戆纥哏鲠笱瞽庋簋刿掴猓蚵槲觳萑癀蟪钬虮掎鲣囝 裥踺茳糨鹪狷麇芤刳愦髡悃缡鲡鳢奁墚尥柃胪镥脔杩劢墁玟蝻呶搦湓罴蜱 俜鲆皤镨槭镪黢洳枘芟埏渖筮殳飧溻饧樘醣酡圬粞觋莶霰榍薤髹曛疋迓衤 欹佾埸霪茚鼬伛瘵骣畛卮轾彘觯锺邾槠谘嵫髭蕞犴鞴畀滗煸褊冫孛羼耖褫 彳艟辶茈璁爨榱萏坫鸫篼簖裰哚蹯瀵怫陔筻廾蛄绲崞蜾盍荭黉糇骺後鲎煳 鹕冱瓠逭漶耠镬齑殛鲚跏蛱搛缣鹣僬噍衿缂喾狯纩栝蛞稂塄嫠詈蠊鹩躐鹨 簏膂脶嬷昴瞀浼艨祢縻蘼芈糸宀眄鹋杪咩愍麽瘼鍪硇猱茑脬蟛貔仳犏钋芑 葜愆锓蠼筌鬈蚺荛埽潲诜埘弑嗍蒴鸶缌澌姒蔌睃缇梃彖鼍芄隈鲔硪忤痦欷 僖醯鼷跣枵忄擤勖痃碹谳轺铘圯纡窬窳饫蓣瀹趱驵缯揸笊絷跖舯螽籀舳粢 驺陬阼揞菝魃癍鹎坌狴萆嬖襞碥髟鳔醭螬馇虿瘥惝怊鸱螭瘛帱徂汆脞瘅忉 羝睇瓞鲽岽胨芏佴燔偾稃郛莩幞澉槔袼搿茛鞲觏酤牿鲴宄匦呙馘焓瘊虍岵 鹱咴隳缋溷夥剞洎恝蒹谫僭艽挢敫卺冂扃锔窭锩觖劂氪骒哙悝蝰诔苈篥娈 瞵锍栊癃舻辂稆猡蛑甍艋敉眇蠛侔镎肭艿蛲疒陧衄锘堋庀擗甓螵钷攴桤褰 凵肷锖鞒吣黥俅蝤璩悛辁肜颡谂礻摅汜溲嗉荽闼骀炱螗耥裼铫莛亠箨蕹迕 杌寤穸饩舄禊猃绁渫廨獬硎荇鸺貅糈揎镟獯讠厣罨蛘鳐崾舣媵尢蚰侑狳螈 龠昃痄搌浈埴夂黹酎橥丶缒窀菹锿砹茇勹邶鐾舭忭缏灬瘭踣钸礤骖黪艚锸 猹镡躔蒇冁鬯屮枨眵傺搋巛舡楱镩鹾戥觌阽铞垤揲蹀耵髑憝鸸鲕篚镄鲼唪 祓艴黻黼鳆尜戤塥哿虼遘桄丨胲醢撖嚆薨堠烀轷锾缳擐哕阍劐攉丌墼蕺彐 芰哜戋趼楗耩喈卩鲒骱刭弪獍鬏鞫犋屦醵桊爝捃胩锎蒈莰闶钶锞眍筘阃漤 铹栳耢仂泐檑轹蔹懔垆锊倮蠃鞔硭漭猸鹛钔瞢礞喵苠鳘貊貘毪坶攮猊嬲肀 聍甯狃耨孥胬恧蒎锫陴氕丿裒镤蜞岍搴箝慊椠蜣硗劁缲檎螓圊檠謦銎赇鼽 糗麴鸲磲畎狨蝾薷襦颥蓐脎毵磉鳋唼歃彡骟滠矧胂蓍鲺贳搠厶兕锼螋瞍觫 赕铴瑭慝掭祧龆蜩鲦茼酴煺柝腽軎阌阢诶菥蓰柙祆筅葙蟓魈躞砉醑儇岈砑 珧酏劓堙撄潆舁蝓燠眢箢掾刖狁拶唣迮帻谮哳齄膪嫜忮骘膣踬荮瘃麈疰丬 浞禚觜耔腙鄹鲰躜撙胙省啰瞭乂丏夬匜厾玕玙抔抃㧐芼旸吽牤沚沨纴玡玭 玠玥玦拤劼拃㧟茓茀杻旻昉呣䏝炘㤘祎祇垱挦剋柈𠳐眊峣郤饸饹疭竑闿羑 浕恓牁姮珰珣琤栟彧眬鸮䥽盉俵俶訚烜浥牂骎琇捯埵捽堉棻梿棁晞唵崚秾 鸻馃阇焗惇郿欸琫琯揳塆靰靸椪雱睄嗞嵖嵎铻媭鲀颎焜湜湲湉愔祾翚瑄蒟 楯跶跐嗐锜鹐亶瘆滫滃滪窣璈叆摽榖靺靿僰豨䁖嘡嘚箓魆粿熥嫚奭鋆瞋颙 踒𥻗熜潟褟璟璠璘縠嚄螠䦃镚镠膙獴赟澥窸璪鞡鞬罽鳀鞨鞧藠蹚鹮霨蹽蹾 齁㸆巉镴臜瓘镵齉卬𠙶毌邘圢伋冮氿汈氾讱扞圲圫芃朳朸𨙸邨屼屾辿伣伈 癿甪邠汋䜣讻孖玒玓玘玚刬坉扽坋扺㧑毐芣苉芠𫇭杕杙杄杧尪尨轪𫐄坒旴 旵㕮岠呇冏觃伾㑇伭佖佁飏汧汫𣲘𣲗沄沘汭㳇沇忳忺祃诇邲诐屃岊䢺妧妘 𨚕纮驲𫘜纻𫘝纼玤玞玱邽邿坥坰坬坽弆䢼𦭜茋苧苾枅㭎枍矼矻匼旿昇昄昒 昈咉咇咍岨岞峂㟃囷钖牥垈侁侹佸佺㑊侂佽侘郈舠郃攽肸狉狝饳忞炌炆泙 沺泂泜泃泇峃祋祊𫍣鸤弢弨陑陎乸妭姈叕䌹𫠊㛃玶珇珅珋玹珌玿韨垚垯垙 垍耇垎垟垞挓垵垏荖荁荙茽荄荓𦰡㭕柷柊枹栐柖郚剅䴓迺厖砆砄耏奓䶮昺 𪾢昽盷咡咺昳昣昤昫昡咥昪虷虸哃峘峏峛𪨰峗峧帡钘𫓧秬俫俙俍垕衎弇侴 鸧䏡胠𦙶胈胣朏飐訄饻庤疢炣炟㶲洭洘洓洿㳚泚浉洸洑洢洈洺洨浐㳘洴洣 恔宬扂袆祏祐祕叚陞娀姞姱姤姶姽枲绖骃𫄧骉珪珛珹玼珖𪟝珽珦珫珒珢珕 珝埗垾垺埆垿埌埇茝鄀莝䓖莙栻梠栴梴栒𫠆砵砠砫硁翃郪𨐈辀剕哢晅晊唝 哱冔晐畖蚄蚆𫑡崁峿𪨶崄帨崀甡倻倴脩倕倞倓倧衃虒舥鸰朓虓鱽峱𫗧勍竘 羖羓烠烔烶烻涍浡浭浬涄涢涐浰浟浛浲涘悈悢宧窅窊窎扅扆袪袗袯隺堲疍 𨺙烝砮㛚翀翂剟𫄨绤骍䂮琎珸珵琄琈琀珺堎堐埼埫堌晢掞埪壸㙍萚莿䓫勚 䓬菂菍菼萣䓨菉䓛梼梽桲梾桯梣梌桹敔硔硙硚硊硍勔䴕龁逴啫翈㫰晙畤跂 蛃蚲啴䎃崟崒崌崡铏𫓯𫟹𫟼铚牻笯偰偡偭偲偁㿠鄅偓徛衒舲鸼悆鄃瓻䝙脟 䏲鱾猇猄𠅤庱庼痓䴔竫堃羕焆烺焌淏淟淜淴淯湴涴㥄惛惔悰惙寁𫍯裈祲𫍲 谞弸弶隃婞娵婼媖婳婍婌婫婤婘婠𫘦绹𫟅骕𫘧絜珷琲琡琟琔琭堾堼揕㙘堧 喆堨塅𪣻𡎚惎萳靬葴鄚蓇萩蒐葰葎鄑葖蒄萹棤棽棫椓椑鹀椆棓棬棪椀甦酦 奡皕詟𫐐辌棐龂牚睎晫晪晱𧿹畯斝喤崶嵁嵅崿嵚翙𫖮圌圐赑赒𨱇𫓶犇颋稌 筀筜筥傃傉翛傒傕畬𫖯脿腘䐃腒鲃猰𫛭猯㺄馉凓鄗廋廆鄌遆旐焞欻𣸣溚溁 湝渰㴔渟溠渼溇湣湑溞愐愃敩棨扊祼婻媆媞㛹媓媂媄矞𫘨缊缐骙瑃瑓瑅瑆 䴖瑖瑝瑔瑀𤧛瑳瑂嶅瑑髢堽赪摛塝搒蒱蒨蓏蔀蓢蓂蒻楪榃榅楒楩椸楙歅碃 碏碈䃅硿鄠辒𫐓䣘暕鹍㬊暅跱蜐蜎嵲赗𫓹锳锧稑稙䅟筼筶筦筤僇艅谼貆腨 腯鲉鲊鲌䲟鲏雊猺飔觟𦝼馌裛鄘鹒鄜麀阘𫔶煁煃煴煋煟煓溍溹滆滉溦溵漷 滧滘滍愭慥慆塱𫌀禋禔禘禒鹔𫖳嫄媱勠戣𫘪𫘬缞耤瑧𫞩瑨瑱瑢斠摏墕墈墐 墘摴𡐓𪤗靽鞁蔈蔊榰榑槚𣗋槜疐酺碶䃎碨𥔲𫚖䴗鹖㬎幖嶍圙𨱏锽镃馝鹙箖 劄僔僎槃㙦𫚕鲖鲗鲘鲙𩽾夐飗凘廙鲝鄫熇漹漖潩漼漴㽏漈漋漻慬㮾褕禛隩 嫕嫭嫪㻬麹璆漦叇墣墦墡薁蕰蔃鼒槱鹝磏殣慭霅暵暲暶踦䗖蝘蝲噇噂噀罶 嶲嶓㠇嶟嶒镈镋镕皞皛䴘艎鹟𩾃鲪鲬觭鹠鹡鹢熛潖潵㵐澂澛瑬潽潾潏憭憕 戭褯禤𫍽嫽遹璥璲璒憙薳黇蕗薢橞橑橦觱磡𥕢磜豮𫟦𫠜虤暿曌曈㬚蹅踶䗛 疁㠓幪𪩘嶦𨱑馞穄篯簉衠盦螣縢鲯鲹𫗴亸羱糒燋熻燊燚燏濩濋澪澽澴澭澼 憺嬛翯𫄷璱𤩽璬璮髽擿薿薸櫆檞醨繄磹磻瞫蹐蟏㘎𫔍𨱔𫔎矰穙穜穟簕簃儦 魋斶谿䲠鲾鲿鳁鳂鳈鳉䗪襕襚螱嬬嬥𦈡𫄸瓀釐鬶爇鞳鞮藟藦藨鹲黡礌𥖨蹢 蹜蟫䗴嚚髃镮酂馧簠簝簰鼫鼩皦臑䲢鳑鳒鹯癗𦒍旞翷䎖瀔瀍瀌襜䴙嚭㰀鬷 蠋翾儳儴𩾌鳚鳛麑麖彟嬿鬒蘘欂甗𨟠巇酅髎犨𨭉㸌爔瀱瀼襫孅骦耰𤫉瓖鬘 趯罍鼱鳠鳡鳣爟爚灈韂糵礵鹴皭龢鳤亹籥𫚭玃醾齇觿" "")) "常用汉字") (defun pyim-pymap-build-pymap () "使用 libpinyin 自带的 data 文件创建 `pyim-pymap'. 这个函数运行估计需要5分钟。" (interactive) (let* ((dir (read-directory-name "请输入 libpinyin 的 data 目录:")) (hash-table (make-hash-table :test #'equal)) (file1 (expand-file-name "gb_char.table" dir)) (file2 (expand-file-name "gbk_char.table" dir))) (with-temp-buffer (when (and (file-exists-p file1) (file-exists-p file2)) (insert-file-contents file1) (insert-file-contents file2) (goto-char (point-min)) (while (not (eobp)) (let* ((contents (pyim-dline-parse)) (code (replace-regexp-in-string "'" "-" (car contents))) (word (cadr contents))) (unless (string-match-p "-" code) (puthash code (push word (gethash code hash-table)) hash-table))) (forward-line 1)))) (insert (with-temp-buffer (maphash (lambda (key value) (let* ((n (- (length pyim-pymap--commonly-used-cchar) 1)) (value (reverse (delete-dups value))) (seps (mapcar (lambda (n) (propertize (nth n pyim-pymap--commonly-used-cchar) 'sep t)) (list 4000 7000 n))) (string (string-join (mapcar (lambda (str) (if (get-text-property 0 'sep str) "|" str)) (sort (append seps value) #'pyim-pymap--cchar<))))) (insert (format "(%S %S)\n" key string)))) hash-table) (sort-lines nil (point-min) (point-max)) (goto-char (point-min)) (insert "(defvar pyim-pymap\n'(") (goto-char (point-max)) (delete-char -1) (insert ")\n\"拼音汉字对照表. 第一个元素为拼音,第二个元素为拼音对应的汉字组成的字符串,字符串 中汉字按照使用频率排序,字符串用 “|” 隔开,分成一级常用汉字,二级 常用汉字,三级常用汉字和不常用汉字。分类方式参考了国务院公布的 《通用规范汉字表》: 国务院关于公布《通用规范汉字表》的通知(国发〔2013〕23号) http://www.gov.cn/zwgk/2013-08/19/content_2469793.htm 但不是完全一致。\")") (emacs-lisp-mode) (indent-region (point-min) (point-max)) (buffer-string))))) (defun pyim-pymap--sort-pymap () "对 `pyim-pymap' 重新排序, 这个函数主要用于维护 `pyim-pymap'." (let (pymap) (dolist (py pyim-pymap) (push (list (car py) (string-join (sort (split-string (cadr py) "") #'pyim-pymap--cchar<))) pymap)) (reverse pymap))) (defun pyim-pymap--cchar< (a b) "如果汉字 A 的使用频率大于汉字 B 的使用频率时,返回 non-nil" (< (or (cl-position a pyim-pymap--commonly-used-cchar :test #'equal) 1000000) (or (cl-position b pyim-pymap--commonly-used-cchar :test #'equal) 1000000))) (defvar pyim-dhashcache-code2word) (defun pyim-pymap-get-duoyinzi-words () (interactive) (pyim-pymap--py2duoyinzi-cache-create t) (let (code2word output) (maphash (lambda (key value) (let* ((pys (split-string key "-")) (length (length pys))) (when (and (> length 1) (< length 3)) (push (cons pys value) code2word)))) pyim-dhashcache-code2word) (dolist (x code2word) (let ((words (cdr x))) (dolist (word words) (let ((chars (remove "" (split-string word ""))) (i 0)) (dolist (char chars) (when-let* (;; 找到这个汉字所有得拼音 (char-pinyins (pyim-pymap-cchar2py-get char)) ;; 判断是不是多音字 (lengthp (> (length char-pinyins) 1)) ;; 剔除已经设置为 fallback 拼音 (char-pinyins (cl-remove-if (lambda (py) (member char (pyim-pymap--py2duoyinzi-get py t))) char-pinyins)) ;; 找到 code2word 词库中,这个字对应得拼音 (pinyin (nth i (car x))) ;; 看这个拼音是否需要特殊处理 (need (member pinyin char-pinyins))) (setf (alist-get pinyin output nil nil #'equal) (sort (delete-dups `(,@(alist-get pinyin output nil nil #'equal) ,word)) #'string<))) (setq i (1+ i))))))) (pp (sort output (lambda (a b) (string< (car a) (car b))))))) ;; * Footer (provide 'pyim-pymap-utils) ;;; pyim-pymap-utils.el ends here pyim-5.3.3/pyim-common.el0000644000175000017500000001762614362212573015141 0ustar dogslegdogsleg;;; pyim-common.el --- common utilities for pyim -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2015-2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;; * 说明文档 :doc: ;; This file has common utilities used by pyim ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'subr-x) (defgroup pyim-common nil "pyim common." :group 'pyim) (defvar pyim-debug nil) (defvar pyim--local-variable-list nil "A list of buffer local variable.") (defun pyim-register-local-variables (vars) "Recode variables VARS to `pyim--local-variable-list'." (dolist (var vars) (cl-pushnew var pyim--local-variable-list) (make-variable-buffer-local var) (put var 'permanent-local t)) pyim--local-variable-list) (defun pyim-kill-local-variables () "Kill all local variables in `pyim--local-variable-list'." (mapc #'kill-local-variable pyim--local-variable-list)) (defun pyim-recreate-local-variables () "Kill then make all variables in `pyim--local-variable-list'." (mapc #'kill-local-variable pyim--local-variable-list) (mapc #'make-local-variable pyim--local-variable-list)) (defun pyim-string-match-p (regexp string &optional start) "与 `string-match-p' 类似,如果 REGEXP 和 STRING 是非字符串时, 不会报错。" (and (stringp regexp) (stringp string) (string-match-p regexp string start))) (defun pyim-dline-parse (&optional seperaters) "解析词库文件当前行的信息,SEPERATERS 为词库使用的分隔符。" (let* ((begin (line-beginning-position)) (end (line-end-position)) (items (split-string (buffer-substring-no-properties begin end) seperaters))) items)) (defun pyim-permutate-list (list) "使用排列组合的方式重新排列 LIST. 这个函数由 \"二中\" 提供。" (let ((list-head (car list)) (list-tail (cdr list))) (cond ((null list-tail) (cl-loop for element0 in list-head append (cons (cons element0 nil) nil))) (t (cl-loop for element in list-head append (mapcar (lambda (l) (cons element l)) (pyim-permutate-list list-tail))))))) (defun pyim-zip (lists &optional care-first-one) "Zip LISTS and delete dups: ((a b c) (d e)) => (a d b e c). When CARE-FIRST-ONE is no-nil, ((a b c) (d e)) => (a d)." (when care-first-one (setq lists (mapcar (lambda (x) (list (car x))) lists))) (setq lists (remove nil lists)) (if (< (length lists) 2) (car lists) (let* ((n (apply #'max (mapcar #'length lists))) (lists (mapcar (lambda (x) (append x (make-list (- n (length x)) nil))) lists))) (delete-dups (pyim-flatten-tree (apply #'cl-mapcar #'list lists)))))) (defun pyim-flatten-tree (tree) "Take TREE and \"flatten\" it." (if (fboundp 'flatten-tree) (flatten-tree tree) (let (elems) (while (consp tree) (let ((elem (pop tree))) (while (consp elem) (push (cdr elem) tree) (setq elem (car elem))) (if elem (push elem elems)))) (if tree (push tree elems)) (nreverse elems)))) (defun pyim-subconcat (list &optional sep) "Concat sublist of LIST with SEP: (a b c d) => (abcd abc ab)." (let ((n (length list)) output) (dotimes (i (- n 1)) (let ((list (cl-subseq list 0 (- n i)))) (push (string-join list (or sep "")) output))) (nreverse output))) (defun pyim-split-list (list separator) "Split LIST into sublists bounded by equal SEPARATOR." (let (group result) (dolist (x (append list (list separator))) (if (not (equal x separator)) (push x group) (push (nreverse group) result) (setq group nil))) (reverse result))) (defun pyim-char-before-to-string (num) "得到光标前第 NUM 个字符,并将其转换为字符串。" (let* ((point (point)) (point-before (- point num))) (when (and (> point-before 0) (char-before point-before)) (char-to-string (char-before point-before))))) (defun pyim-char-after-to-string (num) "得到光标后第 NUM 个字符,并将其转换为字符串。" (let* ((point (point)) (point-after (+ point num))) (when (char-after point-after) (char-to-string (char-after point-after))))) (defun pyim-char-before-to-number (num) (string-to-number (pyim-char-before-to-string num))) (if (fboundp 'string-distance) (defalias 'pyim-string-distance 'string-distance) (defun pyim-string-distance (s1 s2) "Return the edit (levenshtein) distance between strings S1 S2." (let* ((l1 (length s1)) (l2 (length s2)) (dist (vconcat (mapcar (lambda (_) (make-vector (1+ l2) nil)) (number-sequence 1 (1+ l1))))) (in (lambda (i j) (aref (aref dist i) j)))) (setf (aref (aref dist 0) 0) 0) (dolist (j (number-sequence 1 l2)) (setf (aref (aref dist 0) j) j)) (dolist (i (number-sequence 1 l1)) (setf (aref (aref dist i) 0) i) (dolist (j (number-sequence 1 l2)) (setf (aref (aref dist i) j) (min (1+ (funcall in (1- i) j)) (1+ (funcall in i (1- j))) (+ (if (equal (aref s1 (1- i)) (aref s2 (1- j))) 0 1) (funcall in (1- i) (1- j))))))) (funcall in l1 l2)))) (defun pyim-proportion (nums) "计算 NUMS 所占比例。" (let ((sum (float (apply #'+ nums)))) (mapcar (lambda (n) (/ n sum)) nums))) (defun pyim-numbers> (a b) "比较数字列表 A 和 B." (if (and (car a) (car b) (equal (car a) (car b))) (pyim-numbers> (cdr a) (cdr b)) (> (or (car a) 0) (or (car b) 0)))) (defun pyim-add-unread-command-events (key &optional reset) "This function is a fork of `quail-add-unread-command-events'." (when reset (setq unread-command-events nil)) (setq unread-command-events (if (characterp key) (cons (cons 'no-record key) unread-command-events) (append (cl-mapcan (lambda (e) (list (cons 'no-record e))) (append key nil)) unread-command-events)))) ;; Fork from `company-dabbrev--time-limit-while' in company-mode." (defmacro pyim-time-limit-while (test limit &rest body) "If TEST non-nil and time consumption < LIMIT, repeat eval BODY." (declare (indent 2) (debug t)) (let ((start (make-symbol "start"))) `(let ((,start (current-time))) (catch 'done (while ,test ,@body (and ,limit (> (float-time (time-since ,start)) ,limit) (throw 'done 'pyim-time-out))))))) (defvar exwm-xim-buffer-p) (defun pyim-exwm-xim-environment-p () "判断当前环境是否是 exwm-xim 环境。" (bound-and-true-p exwm-xim-buffer-p)) ;; * Footer (provide 'pyim-common) ;;; pyim-common.el ends here pyim-5.3.3/tests/0000755000175000017500000000000014362212573013501 5ustar dogslegdogslegpyim-5.3.3/tests/pyim-emacs-init.el0000644000175000017500000000061014262115565017027 0ustar dogslegdogsleg(require 'pyim) (setq default-input-method "pyim") (setq pyim-debug t) (defun pyim-test-find-file (file) "Read FILE's content into current buffer." (let* ((files (directory-files-recursively default-directory file))) (file-truename (car files)))) (setq pyim-dicts (list (list :name "basedict" :file (pyim-test-find-file "pyim-basedict.pyim")))) (message "pyim-dicts=%s" pyim-dicts) pyim-5.3.3/tests/pyim-byte-compile.el0000644000175000017500000000334114270574720017374 0ustar dogslegdogsleg;;; pyim-byte-compile.el --- syntax check the code -*- lexical-binding: t -*- ;; Copyright (C) 2022 Free Software Foundation, Inc. ;; ;; Author: Chen Bin ;; URL: https://github.com/tumashu/pyim ;; This file is NOT part of GNU Emacs. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, see . ;;; Commentary: ;; Syntax check the pyim code. It's used in Emacs cli. ;; ;;; Code: (require 'find-lisp) (let ((files (find-lisp-find-files-internal "./" (lambda (file dir) (and (not (file-directory-p (expand-file-name file dir))) (string-match "\\.el$" file) (not (string-match "\\.dir-locals.el" file)))) (lambda (dir parent) (not (or (string= dir ".") (string= dir "..") (string= dir ".git") (string= dir ".svn") (string= dir ".deps") (string= dir "tests") (file-symlink-p (expand-file-name dir parent)))))))) (dolist (file files) (byte-compile-file file))) ;;; pyim-byte-compile.el ends here pyim-5.3.3/tests/pyim-tests.el0000644000175000017500000031463214362212573016152 0ustar dogslegdogsleg;;; pyim-tests.el --- unit tests for pyim -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2019-2021 Free Software Foundation, Inc. ;; Author: Chen Bin ;; Maintainer: Chen Bin ;; Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;; pyim test case. ;; 1. [50%] pyim-autoselector.el ;; 2. [90%] pyim-candidates.el ;; 3. [95%] pyim-cloudim.el ;; 4. DONE pyim-codes.el ;; 5. DONE pyim-common.el ;; 6. [95%] pyim-cregexp.el ;; 7. [95%] pyim-cregexp-utils.el ;; 8. DONE pyim-cstring.el ;; 9. DONE pyim-cstring-utils.el ;; 10. DONE pyim-dcache.el ;; 11. [95%] pyim-dhashcache.el ;; 12. DONE pyim-dict.el ;; 13. IGNORE pyim-dict-manager.el ;; 14. [20%] pyim-dregcache.el ;; 15. TODO pyim.el ;; 16. DONE pyim-entered.el ;; 17. DONE pyim-imobjs.el ;; 18. TODO pyim-indicator.el ;; 19. IGNORE pyim-liberime.el ;; 20. TODO pyim-outcome.el ;; 21. [30%] pyim-page.el ;; 22. DONE pyim-pinyin.el ;; 23. [30%] pyim-preview.el ;; 24. [95%] pyim-probe.el ;; 25. TODO pyim-process.el ;; 26. DONE pyim-punctuation.el ;; 27. DONE pyim-pymap.el ;; 28. IGNORE pyim-pymap-utils.el ;; 29 DONE pyim-scheme.el ;;; Code: ;; * 代码 :code: (require 'ert) (require 'pyim) (require 'pyim-basedict) ;pyim-test.el use pyim-basedict v0.5.0. (require 'pyim-cstring-utils) (require 'pyim-cregexp-utils) (require 'pyim-dhashcache) (require 'pyim-dregcache) (require 'pyim-pymap-utils) (defun pyim-tests-make-temp-file (&optional dir-flag) (make-temp-file "pyim-tests-temp-" dir-flag)) (defun pyim-tests-noninteractive-init () (setq default-input-method "pyim") (setq pyim-dicts nil) (setq pyim-extra-dicts nil) ;; 设置 pyim-dcache-directory, 防止用户个人词库不小心被覆盖掉。 (setq pyim-dcache-directory (pyim-tests-make-temp-file t)) ;; 做测试的时候不保存词库,防止因为误操作导致个人词库损坏。 (defalias 'pyim--kill-emacs-hook-function #'ignore) (pyim-basedict-enable) (pyim-dcache-init-variables)) (when noninteractive (pyim-tests-noninteractive-init)) ;; ** pyim-scheme--all-schemes 相关单元测试 (ert-deftest pyim-tests-pyim-scheme--all-schemes () (let ((pyim-default-scheme 'wubi)) (should (equal (pyim-scheme-name (pyim-scheme-current)) 'wubi))) (let ((pyim-default-scheme 'wuci)) (should (equal (pyim-scheme-name (pyim-scheme-current)) 'quanpin))) (let ((pyim-default-scheme 'wubi) (pyim-assistant-scheme 'cangjie) (pyim-scheme--enable-assistant-p t)) (should (equal (pyim-scheme-name (pyim-scheme-current)) 'cangjie))) (let ((pyim-default-scheme 'wubi) (pyim-assistant-scheme 'cangjie) (pyim-scheme--enable-assistant-p nil)) (should (equal (pyim-scheme-name (pyim-scheme-current)) 'wubi))) (should (equal (pyim-scheme-name (pyim-scheme-get 'quanpin)) 'quanpin)) (should-not (pyim-scheme-get 'quanpin1)) (should (equal (pyim-scheme-name (pyim-scheme-get 'wubi)) 'wubi))) (ert-deftest pyim-tests-pyim-scheme-add () (let ((pyim-scheme--all-schemes nil)) (pyim-scheme-add '(quanpin :document "test1" :class quanpin :first-chars "abcdefghijklmnopqrstuwxyz" :rest-chars "vmpfwckzyjqdltxuognbhsrei'-a" :prefer-triggers ("v"))) (pyim-scheme-add '(quanpin :document "test2" :class quanpin :first-chars "abcdefghijklmnopqrstuwxyz" :rest-chars "vmpfwckzyjqdltxuognbhsrei'-a" :prefer-triggers ("v"))) (pyim-scheme-add '(quanpin1 :document "test3" :class quanpin :first-chars "abcdefghijklmnopqrstuwxyz" :rest-chars "vmpfwckzyjqdltxuognbhsrei'-a" :prefer-triggers ("v"))) (pyim-scheme-add "error") (should (equal (mapcar #'pyim-scheme-document pyim-scheme--all-schemes) '("test2" "test3"))))) ;; ** pyim-common 相关单元测试 (ert-deftest pyim-tests-pyim-char-before/after-to-string () (with-temp-buffer (insert "你好世界abc") (print (pyim-char-before-to-string 0)) (should (equal (pyim-char-before-to-string 0) "c")) (should (equal (pyim-char-before-to-string 1) "b")) (backward-char 5) (should (equal (pyim-char-before-to-string 0) "好")) (should (equal (pyim-char-before-to-string 1) "你")) (should (equal (pyim-char-after-to-string 0) "世")) (should (equal (pyim-char-after-to-string 1) "界")))) (ert-deftest pyim-tests-pyim-dline-parse () (with-temp-buffer (insert "ni-hao 你好") (should (equal (pyim-dline-parse) '("ni-hao" "你好")))) (with-temp-buffer (insert "a-b-c-d") (should (equal (pyim-dline-parse "-") '("a" "b" "c" "d")))) (with-temp-buffer (insert "你好 2") (should (equal (pyim-dline-parse) '("你好" "2"))))) (ert-deftest pyim-tests-pyim-permutate-list () (should (equal (pyim-permutate-list '((a b) (c d e) (f))) '((a c f) (a d f) (a e f) (b c f) (b d f) (b e f)))) (should (equal (pyim-permutate-list nil) nil)) (should (equal (pyim-permutate-list '((a))) '((a))))) (ert-deftest pyim-tests-pyim-zip () (should (equal (pyim-zip '((a b "d") nil (1 d) (f) nil)) '(a 1 f b d "d"))) (should (equal (pyim-zip nil) nil))) (ert-deftest pyim-tests-pyim-subconcat () (should (equal (pyim-subconcat '("a" "b" "c" "d")) '("abcd" "abc" "ab"))) (should (equal (pyim-subconcat '("a" "b" "c" "d") "-") '("a-b-c-d" "a-b-c" "a-b"))) (should (equal (pyim-subconcat nil) nil))) (ert-deftest pyim-tests-pyim-split-list () (should (equal (pyim-split-list '(a b sep c d) 'sep) '((a b) (c d)))) (should (equal (pyim-split-list '(sep b sep c sep) 'sep) '(nil (b) (c) nil)))) (ert-deftest pyim-tests-pyim-string-distance () (should (equal (pyim-string-distance "nihaoma" "nihaoma") 0)) (should (equal (pyim-string-distance "nihaoma" "nhm") 4)) (should (equal (pyim-string-distance "nihaoma" "niham") 2)) (should (equal (pyim-string-distance "nihaoma" "nbm") 5)) (should (equal (pyim-string-distance "nihaoma" "wbc") 7)) (should (equal (pyim-string-distance "nihaoma" "ni") 5)) (should (equal (pyim-string-distance "nihaoma" "ci") 6))) (ert-deftest pyim-tests-pyim-add-unread-command-events () (let ((unread-command-events nil)) (if (> emacs-major-version 26) (progn (pyim-add-unread-command-events ?a) (should (equal unread-command-events '((no-record . 97)))) (pyim-add-unread-command-events "b") (should (equal unread-command-events '((no-record . 98) (no-record . 97)))) (pyim-add-unread-command-events "cd") (should (equal unread-command-events '((no-record . 99) (no-record . 100) (no-record . 98) (no-record . 97)))) (pyim-add-unread-command-events "e" t) (should (equal unread-command-events '((no-record . 101)))) (pyim-add-unread-command-events nil t) (should (equal unread-command-events nil))) (pyim-add-unread-command-events ?a) (should (equal unread-command-events '(97))) (pyim-add-unread-command-events "b") (should (equal unread-command-events '(98 97))) (pyim-add-unread-command-events "cd") (should (equal unread-command-events '(99 100 98 97))) (pyim-add-unread-command-events "e" t) (should (equal unread-command-events '(101))) (pyim-add-unread-command-events nil t) (should (equal unread-command-events nil))))) (ert-deftest pyim-tests-pyim-time-limit-while () (let ((time (current-time)) (limit 0.1)) (pyim-time-limit-while t limit t) (should (< (float-time (time-since time)) (* limit 2))))) (ert-deftest pyim-test-pyim-proportion () (should (equal (pyim-proportion '(1 2 3 4)) '(0.1 0.2 0.3 0.4)))) (ert-deftest pyim-test-pyim-numbers> () (should-not (pyim-numbers> '(1) '(3))) (should (pyim-numbers> '(4) '(3))) (should-not (pyim-numbers> '(1 2) '(3 4))) (should-not (pyim-numbers> '(1 2) '(1 2))) (should (pyim-numbers> '(2 2) '(1 1))) (should (pyim-numbers> '(2 2) '(1 3))) (should (pyim-numbers> '(2 2) '(1))) (should-not (pyim-numbers> '(2 2) '(3))) (should-not (pyim-numbers> '(2) '(3 1))) (should (pyim-numbers> '(2) '(1 3)))) ;; ** pyim-pymap 相关单元测试 (ert-deftest pyim-tests-pyim-pymap-split-string () (should (equal (pyim-pymap-split-string "你好 hello 你好") '("你好" " hello " "你好"))) (should (equal (pyim-pymap-split-string "hello 你好 hello 你好 hello") '("hello " "你好" " hello " "你好" " hello"))) (should (equal (pyim-pymap-split-string "你好 hello 你好@") '("你好" " hello " "你好" "@"))) (should (equal (pyim-pymap-split-string "你好 hello 你好,你好") '("你好" " hello " "你好" "," "你好"))) (should (equal (pyim-pymap-split-string "你好 hello 你好" t) '("你" "好" " hello " "你" "好"))) (should (equal (pyim-pymap-split-string "你好") '("你好"))) (should (equal (pyim-pymap-split-string "你好" t) '("你" "好"))) (should (equal (pyim-pymap-split-string "hello") '("hello"))) (should (equal (pyim-pymap-split-string "hello" t) '("hello")))) (ert-deftest pyim-tests-pyim-pymap () (should-not (cl-find-if-not (lambda (x) (= (length (split-string (cadr x) "|")) 4)) pyim-pymap)) (should (equal (pyim-pymap--cchar< "的" "成") t)) (should (equal (pyim-pymap-cchar2py-get "阿") '("e" "a"))) (should (equal (pyim-pymap-cchar2py-get ?阿) '("e" "a"))) (should (equal (pyim-pymap-cchar2py-get "你") '("ni"))) (should (equal (pyim-pymap-cchar2py-get "作") '("zuo"))) (should (equal (pyim-pymap-py2cchar-get "a" t) '("阿啊呵腌|嗄吖锕||錒"))) (should (equal (pyim-pymap-py2cchar-get "a" t t) '("阿" "啊" "呵" "腌" "嗄" "吖" "锕" "錒"))) (should (equal (pyim-pymap-py2cchar-get "a" t t t) '("阿" "啊" "呵" "腌" "|" "嗄" "吖" "锕" "|" "|" "錒"))) (should (equal (pyim-pymap-py2cchar-get "zhua" t) '("抓挝爪||髽|膼撾檛簻"))) (should (equal (pyim-pymap--py2duoyinzi-get "a") '("吖啶" "腌臜"))) (should (pyim-pymap-duoyinzi-include-p "银行")) (should-not (pyim-pymap-duoyinzi-include-p "银子")) (should (equal (pyim-pymap--py2duoyinzi-get "ai" t) '("艾"))) (should (equal (pyim-pymap-str2py-get '"hello你好ma") '(("hello" "ni" "hao" "ma")))) (should (equal (pyim-pymap-str2py-get '"hello你鹢ma") '(("hello" "ni" "yi" "ma") ("hello" "ni" "ni" "ma") ("hello" "ni" "hua" "ma")))) (should (equal (mapcar (lambda (x) (concat (substring x 0 1) (substring x -1))) (pyim-pymap-py2cchar-get "a")) '("阿錒" "爱溾" "厂馣" "昂䇦" "奥泑"))) (should (equal (length (pyim-pymap-py2cchar-get "a")) 5)) (should (equal (length (pyim-pymap-py2cchar-get "z")) 36))) ;; ** pyim-pinyin 相关单元测试 (ert-deftest pyim-tests-pyim-pinyin () ;; pyim-pinyin--get-shenmu (should (equal (pyim-pinyin--get-shenmu "nihao") '("n" . "ihao"))) (should (equal (pyim-pinyin--get-shenmu "ao") '("" . "ao"))) (should (equal (pyim-pinyin--get-shenmu "") '(nil . ""))) ;; pyim-pinyin--valid-charpy-p (should (pyim-pinyin--valid-charpy-p "n" "i")) (should (pyim-pinyin--valid-charpy-p "" "a")) (should (pyim-pinyin--valid-charpy-p "" "ao")) (should-not (pyim-pinyin--valid-charpy-p "n" "k")) (should-not (pyim-pinyin--valid-charpy-p "a" "k")) ;; pyim-pinyin--get-charpy (should (equal (pyim-pinyin--get-charpy "nihao") '(("n" "i" "n" "i") . "hao"))) (should (equal (pyim-pinyin--get-charpy "ao") '(("" "ao" "" "ao") . ""))) (should (equal (pyim-pinyin--get-charpy "nh") '(("n" "" "n" "") . "h"))) ;; pyim-pinyin-split (should (equal (pyim-pinyin-split "n") '(("n" nil "n" nil)))) (should (equal (pyim-pinyin-split "ni") '(("n" "i" "n" "i")))) (should (equal (pyim-pinyin-split "nih") '(("n" "i" "n" "i") ("h" nil "h" nil)))) (should (equal (pyim-pinyin-split "nihao") '(("n" "i" "n" "i") ("h" "ao" "h" "ao")))) (should (equal (pyim-pinyin-split "a") '(("" "a" "" "a")))) (should (equal (pyim-pinyin-split "a") '(("" "a" "" "a")))) (should (equal (pyim-pinyin-split "xian") '(("x" "ian" "x" "ian")))) (should (equal (pyim-pinyin-split "xi'an") '(("" "xi'an" "" "xi'an")))) (should (equal (pyim-pinyin-split "ide") '(("" "ide" "" "ide")))) (should (equal (pyim-pinyin-split "ude") '(("" "ude" "" "ude")))) ;; pyim-pinyin-find-fuzzy (let ((pyim-pinyin-fuzzy-alist '(("en" "eng") ("f" "h")))) (should (equal (pyim-pinyin-find-fuzzy '("f" "en" "f" "en")) '(("f" "en" "f" "en") ("f" "eng" "f" "en") ("h" "en" "f" "en") ("h" "eng" "f" "en")))) (should (equal (pyim-pinyin-find-fuzzy '("h" "en" "h" "en")) '(("h" "en" "h" "en") ("h" "eng" "h" "en") ("f" "en" "h" "en") ("f" "eng" "h" "en")))) (should (equal (pyim-pinyin-find-fuzzy '("f" "eng" "f" "eng")) '(("f" "eng" "f" "eng") ("f" "en" "f" "eng") ("h" "eng" "f" "eng") ("h" "en" "f" "eng")))) (should (equal (pyim-pinyin-find-fuzzy '("h" "eng" "h" "eng")) '(("h" "eng" "h" "eng") ("h" "en" "h" "eng") ("f" "eng" "h" "eng") ("f" "en" "h" "eng")))))) ;; ** pyim-punctuation 相关单元测试 (ert-deftest pyim-tests-pyim-punctuation-p () (should (pyim-punctuation-p ?,)) (should (pyim-punctuation-p ?,)) (should-not (pyim-punctuation-p ?a)) (should-not (pyim-punctuation-p ?1))) (ert-deftest pyim-tests-pyim-punctuation () (with-temp-buffer (insert ",") (pyim-punctuation-translate 'full-width) (should (equal (buffer-string) ",")) (pyim-punctuation-translate 'half-width) (should (equal (buffer-string) ","))) (with-temp-buffer (insert "[]") (backward-char 1) (pyim-punctuation-translate 'full-width) (should (equal (buffer-string) "【】")) (pyim-punctuation-translate 'half-width) (should (equal (buffer-string) "[]"))) (with-temp-buffer (let ((pyim-punctuation--pair-status '(("\"" nil) ("'" nil)))) (insert "[{''}]") (backward-char 3) (pyim-punctuation-translate 'full-width) (should (equal (buffer-string) "【『‘’』】")) (pyim-punctuation-translate 'half-width) (should (equal (buffer-string) "[{''}]")))) (with-temp-buffer (let ((pyim-punctuation--pair-status '(("\"" nil) ("'" nil)))) (insert "[{''}]") (backward-char 3) (pyim-punctuation-translate-at-point) (should (equal (buffer-string) "【『‘’』】")) (pyim-punctuation-translate-at-point) (should (equal (buffer-string) "[{''}]")))) (let ((pyim-punctuation--pair-status '(("\"" nil) ("'" nil)))) (should (equal (pyim-punctuation--return-proper-punct '("'" "‘" "’")) "‘")) (should (equal (pyim-punctuation--return-proper-punct '("'" "‘" "’")) "’")))) ;; ** pyim-entered 相关单元测试 (ert-deftest pyim-tests-pyim-entered () (pyim-entered-with-entered-buffer (erase-buffer) (insert "nihao") (backward-char 3)) (should (equal (pyim-entered-get) "nihao")) (should (equal (pyim-entered-get 'point-before) "ni")) (should (equal (pyim-entered-get 'point-after) "hao")) (pyim-entered-erase-buffer) (should (equal (pyim-entered-get) ""))) (ert-deftest pyim-tests-pyim-entered-in-the-middle-of-entered-p () (pyim-entered-with-entered-buffer (erase-buffer) (insert "nihao") (goto-char (point-min))) (should-not (pyim-entered-in-the-middle-of-entered-p)) (pyim-entered-with-entered-buffer (forward-char 1)) (should (pyim-entered-in-the-middle-of-entered-p)) (pyim-entered-with-entered-buffer (goto-char (point-max))) (should-not (pyim-entered-in-the-middle-of-entered-p)) (pyim-entered-with-entered-buffer (backward-char 1)) (should (pyim-entered-in-the-middle-of-entered-p)) ;; Do not delete. (pyim-entered-erase-buffer)) ;; ** pyim-impobjs 相关单元测试 (ert-deftest pyim-tests-pyim-imobjs () (let ((pyim-pinyin-fuzzy-alist '(("en" "eng") ("in" "ing") ("un" "ong"))) (quanpin (pyim-scheme-get 'quanpin)) (wubi (pyim-scheme-get 'wubi)) (cangjie (pyim-scheme-get 'cangjie)) (pyim-shuangpin (pyim-scheme-get 'pyim-shuangpin))) (should (equal (pyim-imobjs-create "nihao" quanpin) '((("n" "i" "n" "i") ("h" "ao" "h" "ao"))))) (should (equal (pyim-imobjs-create "nh" quanpin) '((("n" "" "n" "") ("h" nil "h" nil))))) (should (equal (pyim-imobjs-create "xi'an" quanpin) '((("x" "i" "x" "i") ("'" "an" "'" "an"))))) (should (equal (pyim-imobjs-create "xian" quanpin) '((("x" "ian" "x" "ian"))))) (should (equal (pyim-imobjs-create "fenyun" quanpin) '((("f" "en" "f" "en") ("y" "un" "y" "un")) (("f" "en" "f" "en") ("y" "ong" "y" "un")) (("f" "eng" "f" "en") ("y" "un" "y" "un")) (("f" "eng" "f" "en") ("y" "ong" "y" "un"))))) (should (equal (pyim-imobjs-create "xian" wubi) '(("xian")))) (should (equal (pyim-imobjs-create "xian" cangjie) '(("xian")))) (should (equal (pyim-imobjs-create "nihc" pyim-shuangpin) '((("n" "i" "n" "i") ("h" "ao" "h" "c"))))))) ;; ** pyim-codes 相关单元测试 (ert-deftest pyim-tests-pyim-codes () (let ((quanpin (pyim-scheme-get 'quanpin)) (wubi (pyim-scheme-get 'wubi)) (cangjie (pyim-scheme-get 'cangjie)) (pyim-shuangpin (pyim-scheme-get 'pyim-shuangpin))) (should (equal (pyim-codes-create (car (pyim-imobjs-create "nihao" quanpin)) quanpin) '("ni" "hao"))) (should (equal (pyim-codes-create (car (pyim-imobjs-create "aaaa" wubi)) wubi) '("wubi/aaaa"))) (should (equal (pyim-codes-create (car (pyim-imobjs-create "aaaa" wubi)) wubi 2) '("wubi/aa"))) (should (equal (pyim-codes-create (car (pyim-imobjs-create "aaaa" wubi)) wubi 1) '("wubi/a"))) (should (equal (pyim-codes-create (car (pyim-imobjs-create "aaaa" cangjie)) cangjie) '("cangjie/aaaa"))))) ;; ** pyim-candidates 相关单元测试 (ert-deftest pyim-tests-pyim-candidates-get-chief () (let ((quanpin (pyim-scheme-get 'quanpin)) (pyim-dhashcache-iword2count-recent-10-words (read "#s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8125 data (:all-words (\"就\" \"不是\" \"如果\" \"是\" \"规则\" \"的\" \"词条\" \"第一位\" \"选择\" \"输入法\") \"如果\" 1 \"的\" 1 \"就\" 1 \"输入法\" 2 \"词条\" 1 \"不是\" 1 \"选择\" 1 \"第一位\" 1 \"规则\" 1 \"是\" 1))")) (pyim-dhashcache-iword2count-recent-50-words (read "#s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8125 data (:all-words (\"就\" \"不是\" \"如果\" \"是\" \"规则\" \"的\" \"词条\" \"第一位\" \"选择\" \"输入法\" \"形码\" \"天\" \"网\" \"呵呵\" \"工\" \"你\" \"天空\" \"蓝天\" \"大地\" \"不好\" \"我\" \"你好\") \"你好\" 1 \"你\" 3 \"我\" 1 \"不好\" 1 \"天空\" 2 \"天\" 3 \"大地\" 1 \"蓝天\" 4 \"工\" 2 \"呵呵\" 1 \"网\" 1 \"形码\" 1 \"输入法\" 1 \"选择\" 1 \"第一位\" 1 \"词条\" 1 \"的\" 1 \"规则\" 1 \"是\" 1 \"如果\" 1 \"不是\" 1 \"就\" 1))")) (personal-words1 '("输入罚" "输入法")) (personal-words2 '("蓝田" "蓝天")) (personal-words3 '("美丽" "魅力"))) ;; 1. 最近输入的10个不同的词中出现一次以上。 (should (equal (pyim-candidates-get-chief quanpin personal-words1 nil) "输入法")) ;; 2. 最近输入的50个不同的词中出现过三次以上。 (should (equal (pyim-candidates-get-chief quanpin personal-words2 nil) "蓝天")) ;; 3. 个人词条中的第一个词。 (should (equal (pyim-candidates-get-chief quanpin personal-words3 nil) "美丽")))) (ert-deftest pyim-tests-pyim-candidates-create-xingma () (let ((wubi (pyim-scheme-get 'wubi)) (pyim-dhashcache-icode2word (read "#s(hash-table size 1642 test equal rehash-size 1.5 rehash-threshold 0.8125 data (\"wubi/aaaa\" (\"工\" \"㠭\") \"wubi/bbbb\" (\"子\" \"子子孙孙孙孙\") \"wubi/cccc\" (\"又\" \"叕\")))")) (pyim-dhashcache-code2word (read "#s(hash-table size 1642 test equal rehash-size 1.5 rehash-threshold 0.8125 data (\"wubi/aaaa\" (\"㠭\") \"wubi/bbbb\" (\"子子孙孙\" \"子\") \"wubi/cccc\" (\"叕\" \"又\")))"))) (should (equal (pyim-candidates-create (pyim-imobjs-create "aaaa" wubi) wubi) '("㠭"))) (should (equal (pyim-candidates-create (pyim-imobjs-create "bbbb" wubi) wubi) '("子" "子子孙孙孙孙" "子子孙孙"))) (should (equal (pyim-candidates-create (pyim-imobjs-create "cccc" wubi) wubi) '("叕" "又"))) (should (equal (pyim-candidates-create (pyim-imobjs-create "aaaabbbb" wubi) wubi) '("㠭子" "㠭子子孙孙孙孙" "㠭子子孙孙"))) (should (equal (pyim-candidates-create (pyim-imobjs-create "aaaabbbbcccc" wubi) wubi) '("㠭子叕" "㠭子又"))))) (ert-deftest pyim-tests-pyim-candidates--znabc-words () (let* ((pyim-dhashcache-code2word (make-hash-table :test #'equal)) (pyim-dhashcache-icode2word (make-hash-table :test #'equal)) (quanpin (pyim-scheme-get 'quanpin)) (imobjs (pyim-imobjs-create "nihaomapengyou" quanpin))) (puthash "ni-hao" (list "你好" "尼耗") pyim-dhashcache-code2word) (puthash "ni-hao-ma" (list "你好吗" "你好马") pyim-dhashcache-code2word) (puthash "ni-hao-ma-peng-you" (list "你好吗朋友" "你好吗喷油") pyim-dhashcache-code2word) (should (equal (pyim-candidates--znabc-words imobjs quanpin) '("你好吗朋友" "你好吗" "你好" "你好吗喷油" "你好马" "尼耗"))) (should (equal (pyim-candidates--znabc-words imobjs quanpin t) '("你好吗朋友" "你好吗" "你好"))))) (ert-deftest pyim-tests-pyim-candidates--jianpin-words () (let* ((pyim-dhashcache-code2word (make-hash-table :test #'equal)) (pyim-dhashcache-icode2word (make-hash-table :test #'equal)) (pyim-dhashcache-ishortcode2word (make-hash-table :test #'equal)) (quanpin (pyim-scheme-get 'quanpin)) (imobjs1 (pyim-imobjs-create "nih" quanpin)) (imobjs2 (pyim-imobjs-create "ni" quanpin))) (puthash "n-h" (list "你好" "你坏" "尼耗" "南好" "内核" "内河") pyim-dhashcache-ishortcode2word) (should (equal (pyim-candidates--jianpin-words imobjs1 quanpin) '("你好" "你坏" "尼耗"))) (should-not (pyim-candidates--jianpin-words imobjs2 quanpin)))) (defun pyim-tests-sublist (list n) (if (>= (length list) n) (cl-subseq list 0 n) list)) (defun pyim-tests-sublists (lists n) (cl-mapcar (lambda (x) (pyim-tests-sublist x n)) lists)) (ert-deftest pyim-tests-sublist () (let ((list '(1 2 3 4 5 6))) (should (equal (pyim-tests-sublist list 7) list)) (should (equal (pyim-tests-sublist list 6) list)) (should (equal (pyim-tests-sublist list 5) '(1 2 3 4 5))))) (ert-deftest pyim-tests-sublists () (let ((lists '((1 2 3) (1 2 3 4 5)))) (should (equal (pyim-tests-sublists lists 4) '((1 2 3) (1 2 3 4)))))) (ert-deftest pyim-tests-pyim-candidates--quanpin-words/first-chars () (let* ((pyim-dhashcache-code2word (make-hash-table :test #'equal)) (pyim-dhashcache-icode2word (make-hash-table :test #'equal)) (pyim-dhashcache-shortcode2word (make-hash-table :test #'equal)) (pyim-dhashcache-ishortcode2word (make-hash-table :test #'equal)) (quanpin (pyim-scheme-get 'quanpin)) (imobjs1 (pyim-imobjs-create "n" quanpin)) (imobjs2 (pyim-imobjs-create "ni" quanpin)) (imobjs3 (pyim-imobjs-create "ni-hao" quanpin))) (puthash "n" (list "你" "您" "妮") pyim-dhashcache-ishortcode2word) (puthash "ni" (list "你" "尼") pyim-dhashcache-icode2word) (puthash "ni" (list "尼" "你") pyim-dhashcache-code2word) (puthash "ni-hao" (list "你好" "尼耗" "呢耗") pyim-dhashcache-icode2word) (puthash "ni-hao" (list "你好" "尼耗") pyim-dhashcache-code2word) (puthash "n-h" (list "你好" "你坏" "尼耗" "南好" "内核" "内河") pyim-dhashcache-ishortcode2word) (should (equal (pyim-tests-sublists (pyim-candidates--quanpin-words imobjs1 quanpin nil) 10) '(("你" "您" "妮") nil))) (should (equal (pyim-tests-sublists (pyim-candidates--quanpin-first-chars imobjs1 quanpin nil) 10) '(nil ("南" "乃" "囊" "脑" "呢" "内" "嫩" "能" "你" "年")))) (should (equal (pyim-tests-sublists (pyim-candidates--quanpin-words imobjs1 quanpin nil) 10) '(("你" "您" "妮") nil))) (should (equal (pyim-tests-sublists (pyim-candidates--quanpin-first-chars imobjs1 quanpin nil) 10) '(nil ("南" "乃" "囊" "脑" "呢" "内" "嫩" "能" "你" "年")))) (should (equal (pyim-tests-sublists (pyim-candidates--quanpin-words imobjs2 quanpin nil) 10) '(("你" "尼") ("尼" "你")))) (should (equal (pyim-tests-sublists (pyim-candidates--quanpin-first-chars imobjs2 quanpin nil) 10) '(("你" "尼" "呢" "泥" "拟" "逆" "倪" "妮" "腻" "匿") nil))) (should (equal (pyim-tests-sublists (pyim-candidates--quanpin-words imobjs3 quanpin nil) 10) '(("你好" "尼耗" "呢耗") ("你好" "尼耗")))) (should (equal (pyim-tests-sublists (pyim-candidates--quanpin-first-chars imobjs3 quanpin nil) 10) '(("你好" "尼耗" "呢耗") nil))) )) (ert-deftest pyim-tests-pyim-candidates--quanpin-personal-words () (let* ((pyim-dhashcache-icode2word (make-hash-table :test #'equal)) (pyim-dhashcache-ishortcode2word (make-hash-table :test #'equal)) (quanpin (pyim-scheme-get 'quanpin)) (imobjs1 (pyim-imobjs-create "n" quanpin)) (imobjs2 (pyim-imobjs-create "ni" quanpin)) (imobjs3 (pyim-imobjs-create "nh" quanpin))) (puthash "n" (list "你" "您" "妮") pyim-dhashcache-ishortcode2word) (puthash "ni" (list "你" "尼") pyim-dhashcache-icode2word) (puthash "n-h" (list "呢耗") pyim-dhashcache-icode2word) (puthash "n-h" (list "你好" "你坏" "尼耗") pyim-dhashcache-ishortcode2word) (should (equal (pyim-candidates--quanpin-personal-words (car imobjs1) quanpin) '("你" "您" "妮"))) (should (equal (pyim-candidates--quanpin-personal-words (car imobjs2) quanpin) '("你" "尼"))) (should (equal (pyim-candidates--quanpin-personal-words (car imobjs3) quanpin) '("呢耗" "你好" "你坏" "尼耗"))))) (ert-deftest pyim-tests-pyim-candidates--quanpin-common-words () (let* ((pyim-dhashcache-code2word (make-hash-table :test #'equal)) (pyim-dhashcache-shortcode2word (make-hash-table :test #'equal)) (quanpin (pyim-scheme-get 'quanpin)) (imobjs1 (pyim-imobjs-create "n" quanpin)) (imobjs2 (pyim-imobjs-create "ni" quanpin)) (imobjs3 (pyim-imobjs-create "nh" quanpin))) (puthash "n" (list "你" "您" "妮") pyim-dhashcache-shortcode2word) (puthash "ni" (list "你" "尼") pyim-dhashcache-code2word) (puthash "n-h" (list "呢耗") pyim-dhashcache-code2word) (puthash "n-h" (list "你好" "你坏" "尼耗") pyim-dhashcache-shortcode2word) (should (equal (pyim-candidates--quanpin-common-words (car imobjs1) quanpin) '("你" "您" "妮"))) (should (equal (pyim-candidates--quanpin-common-words (car imobjs2) quanpin) '("你" "尼"))) (should (equal (pyim-candidates--quanpin-common-words (car imobjs3) quanpin) '("呢耗" "你好" "你坏" "尼耗"))))) (ert-deftest pyim-tests-pyim-candidates--quanpin-first-matched-chars () (let* ((pyim-dhashcache-icode2word (make-hash-table :test #'equal)) (pyim-dhashcache-code2word (make-hash-table :test #'equal)) (quanpin (pyim-scheme-get 'quanpin)) (imobjs (pyim-imobjs-create "nihao" quanpin))) (puthash "ni" (list "你" "呢") pyim-dhashcache-icode2word) (puthash "ni" (list "你" "尼") pyim-dhashcache-code2word) (should (equal (pyim-tests-sublist (pyim-candidates--quanpin-first-matched-chars (car imobjs) quanpin) 10) '("你" "呢" "尼" "泥" "拟" "逆" "倪" "妮" "腻" "匿"))))) (ert-deftest pyim-tests-pyim-candidates--quanpin-first-possible-chars () (let* ((quanpin (pyim-scheme-get 'quanpin)) (imobjs1 (pyim-imobjs-create "ni" quanpin)) (imobjs2 (pyim-imobjs-create "nihao" quanpin))) (should (equal (pyim-tests-sublist (pyim-candidates--quanpin-first-possible-chars (car imobjs1) quanpin) 10) '("你" "年" "娘" "鸟" "摄" "您" "宁" "牛" "尼" "念"))) (should (equal (pyim-tests-sublist (pyim-candidates--quanpin-first-possible-chars (car imobjs2) quanpin) 10) '("你" "年" "娘" "鸟" "摄" "您" "宁" "牛" "尼" "念"))))) (ert-deftest pyim-tests-pyim-candidates--search-buffer () (with-temp-buffer (insert "你好你好你坏你坏你话牛蛤牛和牛蛤牛蛤牛蛤牛蛤牛蛤") (should (equal (pyim-candidates--search-buffer (pyim-cregexp-build "nh" 3 t)) '("牛蛤" "你坏" "你好" "牛和" "你话"))) (let ((words (pyim-candidates--search-buffer (pyim-cregexp-build "nh" 3 t)))) (should (equal (get-text-property 0 :comment (car words)) "(buf)"))))) ;; ** pyim-cstring 相关单元测试 (ert-deftest pyim-tests-pyim-cstring--substrings () (should (equal (pyim-cstring--substrings "我爱北京") '(("我爱北京" 0 4) ("我爱北" 0 3) ("我爱" 0 2) ("爱北京" 1 4) ("爱北" 1 3) ("北京" 2 4)))) (should (equal (pyim-cstring--substrings "我爱北京" 3) '(("我爱北" 0 3) ("我爱" 0 2) ("爱北京" 1 4) ("爱北" 1 3) ("北京" 2 4)))) (let* ((str "我爱北京") (alist (pyim-cstring--substrings "我爱北京" 2)) (key (car (nth 1 alist))) (pos (cdr (nth 1 alist)))) (should (equal (substring str (car pos) (cadr pos)) key)))) (ert-deftest pyim-tests-pyim-cstring-split () (let ((pyim-dhashcache-code2word (make-hash-table :test #'equal)) (str "我爱北京天安门")) ;; Create code2word dcache. (puthash "wo-ai" (list "我爱") pyim-dhashcache-code2word) (puthash "bei-jing" (list "北京") pyim-dhashcache-code2word) (puthash "tian-an" (list "天安") pyim-dhashcache-code2word) (puthash "an-men" (list "安门") pyim-dhashcache-code2word) (puthash "tian-an-men" (list "天安门") pyim-dhashcache-code2word) ;; pyim-cstring-split-to-list (should (equal (pyim-cstring-split-to-list str) '(("安门" 5 7) ("天安" 4 6) ("天安门" 4 7) ("北京" 2 4) ("我爱" 0 2)))) (should (equal (pyim-cstring-split-to-list str 2) '(("安门" 5 7) ("天安" 4 6) ("北京" 2 4) ("我爱" 0 2)))) (should (equal (pyim-cstring-split-to-list str 2) '(("安门" 5 7) ("天安" 4 6) ("北京" 2 4) ("我爱" 0 2)))) (should (equal (pyim-cstring-split-to-list str nil t) '(("天安门" 4 7) ("北京" 2 4) ("我爱" 0 2)))) (should (equal (pyim-cstring-split-to-list str nil t t) '(("安门" 5 7) ("北京" 2 4) ("我爱" 0 2)))) (should (equal (pyim-cstring-split-to-string "我爱北京天安门") "我爱 北京 天安门")) (should (equal (pyim-cstring-split-to-string "haha我爱北京天安门haha") "haha 我爱 北京 天安门 haha")) (should (equal (pyim-cstring-split-to-string "haha我爱北京天安门haha" nil "-") "haha-我爱-北京-天安门-haha")) (should (equal (pyim-cstring-split-to-string "haha 我爱北京天安门 haha" nil "-") "haha -我爱-北京-天安门- haha")) ;; pyim-cstring-split-to-string (should (equal (pyim-cstring-split-to-string "我爱北京天安门" t) "我爱 北京 天 安门")) (should (equal (pyim-cstring-split-to-string "我爱北京天安门" nil "-") "我爱-北京-天安门")) (should (equal (pyim-cstring-split-to-string "我爱北京天安门" nil "-" 2) "我爱-北京-天安-门")))) (ert-deftest pyim-tests-pyim-cstring-to-pinyin () (should (equal (pyim-pymap--possible-cchar-pinyin '("xing" "hang") '("银行")) "hang")) (should-not (pyim-pymap--possible-cchar-pinyin '("xing" "hang") '("不行" "行为"))) (should (equal (pyim-pymap--possible-cchar-pinyin '("bu" "pi") '("不") t) "bu")) (should (equal (pyim-pymap--adjust-duoyinzi '("银" "行" "传" "说") '(("yin") ("xing" "heng" "hang") ("zhuan" "chuan") ("yue" "shuo" "shui"))) '(("yin") ("hang") ("chuan") ("shuo")))) (should (equal (pyim-pymap--adjust-duoyinzi '("银" "行" "很" "行") '(("yin") ("xing" "heng" "hang") ("hen") ("xing" "heng" "hang"))) '(("yin") ("hang") ("hen") ("xing")))) (should (equal (pyim-pymap--adjust-duoyinzi '("银" "行" "行" "业" "很" "行" "不" "行" "也" "行" "行" "也" "行") '(("yin") ("xing" "heng" "hang") ("xing" "heng" "hang") ("ye") ("hen") ("xing" "heng" "hang") ("dun" "bu") ("xing" "heng" "hang") ("ye") ("xing" "heng" "hang") ("xing" "heng" "hang") ("ye") ("xing" "heng" "hang"))) '(("yin") ("hang") ("hang") ("ye") ("hen") ("xing") ("bu") ("xing") ("ye") ("xing") ("xing") ("ye") ("xing")))) ;; pyim-cstring-split-to-list (should (equal (pyim-cstring-to-pinyin "银行传说") "yinhangchuanshuo")) (should (equal (pyim-cstring-to-pinyin "银行传说" t) "yhcs")) (should (equal (pyim-cstring-to-pinyin "银行传说" nil "-") "yin-hang-chuan-shuo")) (should (equal (pyim-cstring-to-pinyin "银行传说" nil "-" t) '("yin-hang-chuan-shuo"))) (should (equal (pyim-cstring-to-pinyin "银行传说" nil "-" t t) '("yin-hang-chuan-shuo"))) (should (equal (pyim-cstring-to-pinyin "Hello 银行传说 Hi" nil "-" nil t) "Hello -yin-hang-chuan-shuo- Hi")) ;; FIXME: 这个 test 是不合理的,不过暂时找不到简单的修复方式。 (should (equal (pyim-cstring-to-pinyin "Hello 银行传说 Hi" nil "-" nil nil t) "Hello -yin-hang-chuan-shuo- Hi"))) (ert-deftest pyim-tests-pyim-cstring-to-xingma () (let ((pyim-dhashcache-word2code (make-hash-table :test #'equal)) (wubi (pyim-scheme-get 'wubi)) (cangjie (pyim-scheme-get 'cangjie))) (puthash "工" (list "wubi/aaaa" "cangjie/mlm" "gong") pyim-dhashcache-word2code) (puthash "房" (list "wubi/yny") pyim-dhashcache-word2code) (puthash "丛" (list "wubi/wwg") pyim-dhashcache-word2code) (should (equal (pyim-cstring-to-xingma "工" cangjie) "mlm")) (should-not (pyim-cstring-to-xingma "工房" cangjie)) (should (equal (pyim-cstring-to-xingma "工" wubi) "aaaa")) (should (equal (pyim-cstring-to-xingma "工房" wubi) "aayn")) (should (equal (pyim-cstring-to-xingma "工房丛" wubi) "ayww")) (should (equal (pyim-cstring-to-xingma "工房丛房" wubi) "aywy")) (should (equal (pyim-cstring-to-xingma "工" wubi t) '("aaaa"))) (should (equal (pyim-cstring-to-xingma "工房" wubi t) '("aayn"))))) (ert-deftest pyim-tests-pyim-cstring-to-codes () (let ((pyim-dhashcache-word2code (make-hash-table :test #'equal)) (pyim-dhashcache-word2code (make-hash-table :test #'equal)) (quanpin (pyim-scheme-get 'quanpin)) (wubi (pyim-scheme-get 'wubi)) (cangjie (pyim-scheme-get 'cangjie))) (should (equal (pyim-cstring-to-codes "行行" quanpin "xinxin") '("xing-xing"))) (should (equal (pyim-cstring-to-codes "行行" quanpin "xx") '("xing-xing"))) (puthash "工" (list "wubi/aaaa" "cangjie/mlm" "gong") pyim-dhashcache-word2code) (puthash "房" (list "wubi/yny") pyim-dhashcache-word2code) (puthash "丛" (list "wubi/wwg") pyim-dhashcache-word2code) (should (equal (pyim-cstring-to-codes "工" cangjie) '("mlm"))) (should-not (pyim-cstring-to-codes "工房" cangjie)) (should (equal (pyim-cstring-to-codes "工" wubi) '("aaaa"))) (should (equal (pyim-cstring-to-codes "工房" wubi) '("aayn"))) (should (equal (pyim-cstring-to-codes "工房丛" wubi) '("ayww"))) (should (equal (pyim-cstring-to-codes "工房丛房" wubi) '("aywy"))) (should (equal (pyim-cstring-to-codes "工" wubi t) '("aaaa"))) (should (equal (pyim-cstring-to-codes "工房" wubi t) '("aayn"))))) (ert-deftest pyim-tests-pyim-cstring-words-at-point () (let ((pyim-dhashcache-code2word (make-hash-table :test #'equal))) (puthash "tian-an" (list "天安") pyim-dhashcache-code2word) (puthash "an-men" (list "安门") pyim-dhashcache-code2word) (puthash "tian-an-men" (list "天安门") pyim-dhashcache-code2word) (with-temp-buffer (insert "天安门abc\n天安门") ;; 天安门abc (goto-char (point-min)) (should (equal (pyim-cstring-words-at-point) nil)) ;; 天安门abc (forward-char 1) (should (equal (pyim-cstring-words-at-point) '(("天安门" 1 2) ("天安" 1 1)))) ;; 天安门abc (forward-char 5) (should (equal (pyim-cstring-words-at-point) '(("abc" 3 0)))) ;; 天安门 (forward-char 1) (should (equal (pyim-cstring-words-at-point) nil)) ;; 天安门 (goto-char (point-max)) (should (equal (pyim-cstring-words-at-point) '(("天安门" 3 0) ("安门" 2 0)))) ;; 天安门abc (goto-char (point-min)) (should (equal (pyim-cstring-words-at-point t) nil))))) (ert-deftest pyim-tests-pyim-cstring-forward-or-backward-word () (with-temp-buffer (let ((pyim-dhashcache-code2word (make-hash-table :test #'equal))) (puthash "ha-ha" (list "哈哈") pyim-dhashcache-code2word) (puthash "wo-ai" (list "我爱") pyim-dhashcache-code2word) (puthash "bei-jing" (list "北京") pyim-dhashcache-code2word) (puthash "tian-an-men" (list "天安门") pyim-dhashcache-code2word) (insert "哈哈我爱北京天安门") (goto-char 2) (pyim-cstring-forward-word 1) (should (equal (buffer-substring (point-min) (point)) "哈哈")) (pyim-cstring-forward-word 3) (should (equal (buffer-substring (point-min) (point)) "哈哈我爱北京天安门")) (pyim-cstring-backward-word 1) (should (equal (buffer-substring (point-min) (point)) "哈哈我爱北京")) (pyim-cstring-backward-word 2) (should (equal (buffer-substring (point-min) (point)) "哈哈"))))) ;; ** pyim-cregexp 相关单元测试 (ert-deftest pyim-tests-pyim-cregexp--valid-p () (should-not (pyim-cregexp--valid-p "\\")) (should (pyim-cregexp--valid-p "\\\\")) (should (pyim-cregexp--valid-p "a"))) (ert-deftest pyim-tests-pyim-cregexp--find-scheme () (should-not (pyim-cregexp--find-scheme nil)) (should (equal (pyim-scheme-name (pyim-cregexp--find-scheme 'wubi)) 'wubi)) (should-not (pyim-cregexp--find-scheme 'wubi1)) (should (equal (pyim-scheme-name (pyim-cregexp--find-scheme (pyim-scheme-get 'wubi))) 'wubi))) (ert-deftest pyim-tests-pyim-cregexp--scheme () (let ((wubi (pyim-scheme-get 'wubi))) (should (equal (pyim-scheme-name (pyim-cregexp--scheme wubi)) 'wubi))) (let ((wubi (pyim-scheme-get 'wubi1)) (pyim-default-scheme 'quanpin)) (should (equal (pyim-scheme-name (pyim-cregexp--scheme wubi)) 'quanpin))) (let ((pyim-default-scheme 'quanpin)) (should (equal (pyim-scheme-name (pyim-cregexp--scheme)) 'quanpin))) (let ((pyim-default-scheme 'quanpin1) (pyim-cregexp-fallback-scheme 'wubi)) (should (equal (pyim-scheme-name (pyim-cregexp--scheme)) 'wubi))) (let ((pyim-default-scheme 'quanpin1) (pyim-cregexp-fallback-scheme 'wubi1)) (should (equal (pyim-scheme-name (pyim-cregexp--scheme)) 'quanpin)))) (ert-deftest pyim-tests-pyim-cregexp () ;; FIXME: 这个 test 有问题,以后需要更新。 (let ((regexp (pyim-cregexp-build "ni\\hao"))) (should (string-match-p regexp "nihao")) (should (string-match-p regexp "anihaob")) (should (string-match-p regexp "你好")) (should (string-match-p regexp "哈哈你好吗"))) (let ((regexp (pyim-cregexp-build "nihao"))) (should (string-match-p regexp "nihao")) (should (string-match-p regexp "anihaob")) (should (string-match-p regexp "你好")) (should (string-match-p regexp "哈哈你好吗"))) (let ((regexp (pyim-cregexp-build "nihao" nil t))) (should-not (string-match-p regexp "nihao")) (should-not (string-match-p regexp "anihaob")) (should (string-match-p regexp "你好")) (should (string-match-p regexp "哈哈你好吗"))) (let ((regexp (pyim-cregexp-build "beng"))) (should (string-match-p regexp "痭")) (should (string-match-p regexp "泵")) (should (string-match-p regexp "堋")) (should (string-match-p regexp "洴"))) (let ((regexp (pyim-cregexp-build "ni.*ma"))) (should (string-match-p regexp "nihaoma")) (should (string-match-p regexp "nima")) (should (string-match-p regexp "你好吗")) (should (string-match-p regexp "你不好吗")) (should (string-match-p regexp "哈哈你不好吗"))) (let ((regexp (pyim-cregexp-build "nh"))) (should (string-match-p regexp "nh")) (should (string-match-p regexp "anhb")) (should (string-match-p regexp "你好")) (should (string-match-p regexp "牛哈")) (should (string-match-p regexp "摄和"))) (let ((regexp (pyim-cregexp-build "nha"))) (should (string-match-p regexp "nha")) (should (string-match-p regexp "anhab")) (should (string-match-p regexp "你哈")) (should (string-match-p regexp "牛蛤"))) (let* ((str (nth 2 (split-string (car (pyim-pymap-py2cchar-get "wang" t)) "|"))) (quanpin (pyim-scheme-get 'quanpin)) (regexp1 (pyim-cregexp--create-cregexp-from-string "wang" quanpin 3 nil)) (regexp2 (pyim-cregexp--create-cregexp-from-string "wang" quanpin 2))) (should (string-match-p regexp1 str)) (should-not (string-match-p regexp2 str))) (let* ((quanpin (pyim-scheme-get 'quanpin)) (imobj '(("d" "a" "d" "a") ("w" "ang" "w" "ang"))) (regexp1 (pyim-cregexp-create-from-imobj imobj quanpin)) (regexp2 (pyim-cregexp-create-from-imobj imobj quanpin nil nil t))) (should (string-match-p regexp1 "大王")) (should (string-match-p regexp1 "当王")) (should (string-match-p regexp2 "大王")) (should-not (string-match-p regexp2 "当王"))) (let ((pyim-default-scheme 'wubi) (wubi (pyim-scheme-get 'wubi)) (pyim-dhashcache-code2word (make-hash-table :test #'equal))) (puthash "wubi/aaaa" (list "工" "恭恭敬敬") pyim-dhashcache-code2word) (puthash "wubi/adww" (list "欺" "蒙古人" "其人" "欺人" "斯人" "惹人" "匧" "歁" "莢") pyim-dhashcache-code2word) (should (equal (pyim-cregexp-build "aaaa") "\\(?:aaaa\\|[工恭]恭?敬?敬?\\)")) (should (equal (pyim-cregexp-build "adww") "\\(?:adww\\|[其匧惹斯欺歁莢蒙][人古]?人?\\)")) (should (equal (pyim-cregexp-build "aaaa'aaaa") "\\(?:\\(?:aaaa'\\|aaaa\\|[工恭]恭?敬?敬?\\)\\(?:aaaa\\|[工恭]恭?敬?敬?\\)\\)")) (should (equal (pyim-cregexp--create-cregexp-from-string "aaaa'aaaa" wubi) "\\(?:aaaa'\\|aaaa\\|[工恭][恭]?[敬]?[敬]?\\)\\(?:aaaa\\|[工恭][恭]?[敬]?[敬]?\\)")) (should (equal (pyim-cregexp--build-xingma-regexp-from-words '("工" "恭恭敬敬")) "[工恭][恭]?[敬]?[敬]?")) ) (with-temp-buffer (insert "haha nihao") (let ((pyim-cregexp-convert-at-point-function (lambda (cregexp) (concat "XXX: " cregexp))) (string "\\(?:nihao\\|[㒟㖏㖕㖖㖻㘈㘝㘨㘿㙞㚔㜤㜦㜵㜸㝕㞋㞙㞾㟧㠜㠡㡪㣇㣷㤛㥾㦐㧱㩘㩶㪒㭤㮆㮏㮞㮟㲡㲰㲻㲽㳮㴪㵫㸎㹸㺲㼭㽱㿦䀑䀔䁥䂇䂼䃵䄒䄭䄹䆨䇣䋴䋻䌜䌰䍲䏔䐁䒜䔭䕥䖆䗿䘌䘦䘽䙚䚓䚾䛏䛘䜆䜓䝚䞕䟢䡾䤔䦊䦵䧇䧔䩞䬯䭃䭢䭲䮍䮗䮘䯀䯅䯵䰯䳖䴴䵑䵒乜伱伲佞你侫倪儗儜儞兒凝匿卄呢咛唸啮喦嗫噛嚀嚙囁囐囓囜圼坭埝埿堄妞妮妳姩娘婗嫋嫟嬝嬢嬣嬲嬺孃孨孴孼孽宁寍寕寗寜寧尼尿屔屰峊嵲嶭巕帇年廿念忸怓怩恁您惄惗愵慝懝扭抐抝抳拈拗拟拧拰捏捻掜揑摂摄摰撚撵擜擬擰攆敜旎昵晲暱杻枿柅柠棿榐槷樢橣檷檸櫱氼氽汼沑泞泥涅涊淣淰湼溓溺濘炄牛牜狃狋狔狞猊獰甯疌疒痆眤睨矃碾祢禰秊秜秥篞簐籋籾粘糱糵紐縌纽聂聍聶聹聻胒脲腝腻膩臡臬臲艌苧苨苶茑茮莥菍蔦蔫薴薿蘖蘗蚭蚴蛪蜺蠥衂衵袅裊褭褹觬誽諗譺讘貎跈跜踂踗蹍蹑蹨躎躡輗輦輾辇辗迡逆郳酿醸釀鈕鈢鈮鉨鉩銸鋷錜鎳鑈鑏鑷钀钮铌镊镍闑陧隉隬霓靵顳颞馜鬡鬤鮎鯓鯢鯰鲇鲵鲶鳥鶂鷊鸋鸟鸮鹝鹢麑黏鼰齞齧齯][㕺㘪㙱㚪㝀㞻㠙㩝㬔㬶㵆䒵䚽䝞䝥䧚䧫䪽䬉䯫侾傐儫勂号呺哠嗥嘷噑嚆嚎壕好峼恏悎昊昦晧暠暤暭曍椃毫浩淏滈澔濠瀥灏灝狢獆獋獔皓皜皞皡皥秏竓籇耗聕茠蒿薃薅薧藃號虠蚝蠔諕譹诐豪貉郝鄗鎬镐顥颢鰝鶴鸮]\\)")) (pyim-cregexp-convert-at-point) (should (equal (buffer-string) (concat "haha XXX: " string))))) (with-temp-buffer (insert "hinihao") (set-mark 3) (let ((pyim-cregexp-convert-at-point-function (lambda (cregexp) (concat "XXX: " cregexp))) (string "\\(?:nihao\\|[㒟㖏㖕㖖㖻㘈㘝㘨㘿㙞㚔㜤㜦㜵㜸㝕㞋㞙㞾㟧㠜㠡㡪㣇㣷㤛㥾㦐㧱㩘㩶㪒㭤㮆㮏㮞㮟㲡㲰㲻㲽㳮㴪㵫㸎㹸㺲㼭㽱㿦䀑䀔䁥䂇䂼䃵䄒䄭䄹䆨䇣䋴䋻䌜䌰䍲䏔䐁䒜䔭䕥䖆䗿䘌䘦䘽䙚䚓䚾䛏䛘䜆䜓䝚䞕䟢䡾䤔䦊䦵䧇䧔䩞䬯䭃䭢䭲䮍䮗䮘䯀䯅䯵䰯䳖䴴䵑䵒乜伱伲佞你侫倪儗儜儞兒凝匿卄呢咛唸啮喦嗫噛嚀嚙囁囐囓囜圼坭埝埿堄妞妮妳姩娘婗嫋嫟嬝嬢嬣嬲嬺孃孨孴孼孽宁寍寕寗寜寧尼尿屔屰峊嵲嶭巕帇年廿念忸怓怩恁您惄惗愵慝懝扭抐抝抳拈拗拟拧拰捏捻掜揑摂摄摰撚撵擜擬擰攆敜旎昵晲暱杻枿柅柠棿榐槷樢橣檷檸櫱氼氽汼沑泞泥涅涊淣淰湼溓溺濘炄牛牜狃狋狔狞猊獰甯疌疒痆眤睨矃碾祢禰秊秜秥篞簐籋籾粘糱糵紐縌纽聂聍聶聹聻胒脲腝腻膩臡臬臲艌苧苨苶茑茮莥菍蔦蔫薴薿蘖蘗蚭蚴蛪蜺蠥衂衵袅裊褭褹觬誽諗譺讘貎跈跜踂踗蹍蹑蹨躎躡輗輦輾辇辗迡逆郳酿醸釀鈕鈢鈮鉨鉩銸鋷錜鎳鑈鑏鑷钀钮铌镊镍闑陧隉隬霓靵顳颞馜鬡鬤鮎鯓鯢鯰鲇鲵鲶鳥鶂鷊鸋鸟鸮鹝鹢麑黏鼰齞齧齯][㕺㘪㙱㚪㝀㞻㠙㩝㬔㬶㵆䒵䚽䝞䝥䧚䧫䪽䬉䯫侾傐儫勂号呺哠嗥嘷噑嚆嚎壕好峼恏悎昊昦晧暠暤暭曍椃毫浩淏滈澔濠瀥灏灝狢獆獋獔皓皜皞皡皥秏竓籇耗聕茠蒿薃薅薧藃號虠蚝蠔諕譹诐豪貉郝鄗鎬镐顥颢鰝鶴鸮]\\)")) (pyim-cregexp-convert-at-point) (should (equal (buffer-string) (concat "hiXXX: " string)))))) (ert-deftest pyim-tests-pyim-cregexp--quanpin-get-pinyin-list () (should (equal (pyim-cregexp--quanpin-get-pinyin-list '(("n" "i" "n" "i") ("h" "ao" "h" "ao"))) '("ni" "hao")))) (ert-deftest pyim-tests-pyim-cregexp--quanpin-get-cchars-from-pinyin-list () (should (equal (pyim-cregexp--quanpin-get-cchars-from-pinyin-list '("ni" "hao") nil nil nil) '("你尼呢泥拟逆倪妮腻匿霓溺旎昵坭铌鲵伲怩睨祢疒猊慝鹝鹢薿麑懝兒䮘㧱聻㮞檷䀑抐誽䍲㮏㲡䘌縌㠜儞䘦鈮䰯伱愵嬺氼䘽䵑䵒屔婗䝚䁥䕥孨㵫屰䭲孴㹸譺㥾籾㦐㪒馜隬蚭抳䦵㲻㞾痆㣇䧇狋䛏胒鯓狔秜跜嫟迡鯢淣苨擬觬埿鑈棿腝蛪㘈眤㩘晲掜禰妳堄儗輗蜺鉨齯鶂貎膩暱惄柅鷊臡郳衵年念粘辗碾廿捻撵拈蔫鲶埝鲇辇黏䟢㮟䧔痆攆簐㘝輦䄭䬯鼰䄹艌䩞蹨㞋躎鮎䚓撚㲽跈秊秥姩鯰㜤䴴輾蹍榐唸卄齞涊淰溓娘酿孃䖆釀嬢醸鸟尿溺袅脲氽茑嬲鸮㼭茮樢䐁㠡蔦褭㜵䙚㭤䦊䮍㞙㒟裊鳥㳮䃵嬝嫋枿摄聂捏涅镍孽坭蘖啮蹑嗫臬镊颞乜陧菍嵲糵㟧㖕䞕峊㜦䜆籋䇣㘨䡾㖏䳖痆㘝踂帇㸎䄒䜓踗䌜錜鈢蠥㴪㜸圼㘿鑈噛㙞鉩㡪顳㩶聶鑷孼钀㮆隉疌㚔㖖嚙躡鎳䂼䯀囁䯅揑巕惗擜篞櫱䯵棿䭃䌰諗褹掜槷囐鋷讘銸嶭蘗摰鉨摂敜齧湼枿闑囓糱臲苶喦您恁㤛䚾䛘囜拰䋻宁凝拧泞柠咛坭狞佞聍甯苧䆨薴濘鸋鬡嬣䔭鑏㝕䭢橣獰聹嚀侫㲰檸矃寍寕寗寜㿦寧擰㣷䗿㩶鬤儜牛纽扭钮拗妞蚴忸狃杻䮗抝牜莥䤔㽱䂇怓紐䀔鈕靵汼炄䒜㺲䏔䋴衂沑㖻" "好号毫豪耗浩郝皓昊镐蒿壕灏嚎濠蚝貉颢嗥薅嚆鸮诐淏鄗皞椃䬉㬔蠔㠙鰝瀥昦㘪儫㬶嘷㝀㵆獆籇獋恏噑獔聕㩝灝䝞號虠䝥顥晧㙱㕺悎傐皡暤皥㚪暭鶴䒵㞻䚽䪽侾勂滈曍䧚哠狢䧫䯫峼鎬竓藃譹薃澔皜秏諕暠薧呺茠") )) (should (equal (pyim-cregexp--quanpin-get-cchars-from-pinyin-list '("ni" "hao") nil t nil) '("你尼呢泥拟逆倪妮腻匿霓溺旎昵坭铌鲵伲怩睨祢疒猊慝鹝鹢薿麑懝兒䮘㧱聻㮞檷䀑抐誽䍲㮏㲡䘌縌㠜儞䘦鈮䰯伱愵嬺氼䘽䵑䵒屔婗䝚䁥䕥孨㵫屰䭲孴㹸譺㥾籾㦐㪒馜隬蚭抳䦵㲻㞾痆㣇䧇狋䛏胒鯓狔秜跜嫟迡鯢淣苨擬觬埿鑈棿腝蛪㘈眤㩘晲掜禰妳堄儗輗蜺鉨齯鶂貎膩暱惄柅鷊臡郳衵" "好号毫豪耗浩郝皓昊镐蒿壕灏嚎濠蚝貉颢嗥薅嚆鸮诐淏鄗皞椃䬉㬔蠔㠙鰝瀥昦㘪儫㬶嘷㝀㵆獆籇獋恏噑獔聕㩝灝䝞號虠䝥顥晧㙱㕺悎傐皡暤皥㚪暭鶴䒵㞻䚽䪽侾勂滈曍䧚哠狢䧫䯫峼鎬竓藃譹薃澔皜秏諕暠薧呺茠"))) (should (equal (pyim-cregexp--quanpin-get-cchars-from-pinyin-list '("ni" "hao") t nil nil) '("你尼呢泥拟逆倪妮腻匿霓溺旎昵坭铌鲵伲怩睨祢疒猊慝鹝鹢薿麑懝兒䮘㧱聻㮞檷䀑抐誽䍲㮏㲡䘌縌㠜儞䘦鈮䰯伱愵嬺氼䘽䵑䵒屔婗䝚䁥䕥孨㵫屰䭲孴㹸譺㥾籾㦐㪒馜隬蚭抳䦵㲻㞾痆㣇䧇狋䛏胒鯓狔秜跜嫟迡鯢淣苨擬觬埿鑈棿腝蛪㘈眤㩘晲掜禰妳堄儗輗蜺鉨齯鶂貎膩暱惄柅鷊臡郳衵" "好号毫豪耗浩郝皓昊镐蒿壕灏嚎濠蚝貉颢嗥薅嚆鸮诐淏鄗皞椃䬉㬔蠔㠙鰝瀥昦㘪儫㬶嘷㝀㵆獆籇獋恏噑獔聕㩝灝䝞號虠䝥顥晧㙱㕺悎傐皡暤皥㚪暭鶴䒵㞻䚽䪽侾勂滈曍䧚哠狢䧫䯫峼鎬竓藃譹薃澔皜秏諕暠薧呺茠"))) (should (equal (pyim-cregexp--quanpin-get-cchars-from-pinyin-list '("ni" "hao") t nil 1) '("你尼呢泥拟逆倪妮腻匿霓溺" "好号毫豪耗浩郝皓昊镐蒿壕"))) (should (equal (pyim-cregexp--quanpin-get-cchars-from-pinyin-list '("ni" "hao") t nil 2) '("你尼呢泥拟逆倪妮腻匿霓溺旎昵坭铌鲵伲怩睨祢疒猊慝" "好号毫豪耗浩郝皓昊镐蒿壕灏嚎濠蚝貉颢嗥薅嚆鸮"))) (should (equal (pyim-cregexp--quanpin-get-cchars-from-pinyin-list '("ni" "hao") t nil 3) '("你尼呢泥拟逆倪妮腻匿霓溺旎昵坭铌鲵伲怩睨祢疒猊慝鹝鹢薿麑" "好号毫豪耗浩郝皓昊镐蒿壕灏嚎濠蚝貉颢嗥薅嚆鸮诐淏鄗皞") )) (should (equal (pyim-cregexp--quanpin-get-cchars-from-pinyin-list '("ni" "hao") t nil 4) '("你尼呢泥拟逆倪妮腻匿霓溺旎昵坭铌鲵伲怩睨祢疒猊慝鹝鹢薿麑懝兒䮘㧱聻㮞檷䀑抐誽䍲㮏㲡䘌縌㠜儞䘦鈮䰯伱愵嬺氼䘽䵑䵒屔婗䝚䁥䕥孨㵫屰䭲孴㹸譺㥾籾㦐㪒馜隬蚭抳䦵㲻㞾痆㣇䧇狋䛏胒鯓狔秜跜嫟迡鯢淣苨擬觬埿鑈棿腝蛪㘈眤㩘晲掜禰妳堄儗輗蜺鉨齯鶂貎膩暱惄柅鷊臡郳衵" "好号毫豪耗浩郝皓昊镐蒿壕灏嚎濠蚝貉颢嗥薅嚆鸮诐淏鄗皞椃䬉㬔蠔㠙鰝瀥昦㘪儫㬶嘷㝀㵆獆籇獋恏噑獔聕㩝灝䝞號虠䝥顥晧㙱㕺悎傐皡暤皥㚪暭鶴䒵㞻䚽䪽侾勂滈曍䧚哠狢䧫䯫峼鎬竓藃譹薃澔皜秏諕暠薧呺茠"))) (should (equal (pyim-cregexp--quanpin-get-cchars-from-pinyin-list '("ni" "hao") t nil 5) '("你尼呢泥拟逆倪妮腻匿霓溺旎昵坭铌鲵伲怩睨祢疒猊慝鹝鹢薿麑懝兒䮘㧱聻㮞檷䀑抐誽䍲㮏㲡䘌縌㠜儞䘦鈮䰯伱愵嬺氼䘽䵑䵒屔婗䝚䁥䕥孨㵫屰䭲孴㹸譺㥾籾㦐㪒馜隬蚭抳䦵㲻㞾痆㣇䧇狋䛏胒鯓狔秜跜嫟迡鯢淣苨擬觬埿鑈棿腝蛪㘈眤㩘晲掜禰妳堄儗輗蜺鉨齯鶂貎膩暱惄柅鷊臡郳衵" "好号毫豪耗浩郝皓昊镐蒿壕灏嚎濠蚝貉颢嗥薅嚆鸮诐淏鄗皞椃䬉㬔蠔㠙鰝瀥昦㘪儫㬶嘷㝀㵆獆籇獋恏噑獔聕㩝灝䝞號虠䝥顥晧㙱㕺悎傐皡暤皥㚪暭鶴䒵㞻䚽䪽侾勂滈曍䧚哠狢䧫䯫峼鎬竓藃譹薃澔皜秏諕暠薧呺茠"))) ) ;; ** pyim-import 相关单元测试 (ert-deftest pyim-tests-pyim-import-words-and-counts () ;; 这个测试目前主要用于手工测试,在 github 上这个测试无法通过的。 (when (not noninteractive) (let ((pyim-dcache-directory (pyim-tests-make-temp-file t)) (file (pyim-tests-make-temp-file))) ;; 删除测试用词条 (dolist (x '("测㤅" "测嘊" "测伌")) (pyim-process-delete-word x)) (dolist (x '("测㤅" "测嘊" "测伌")) (should-not (member x (pyim-dcache-get "ce-ai" '(icode2word))))) (should-not (equal (gethash "测㤅" pyim-dhashcache-iword2count) 76543)) (should-not (equal (gethash "测嘊" pyim-dhashcache-iword2count) 34567)) (should-not (equal (gethash "测伌" pyim-dhashcache-iword2count) 0)) ;; 导入测试用词条 (with-temp-buffer (insert ";;; -*- coding: utf-8-unix -*- 测㤅 76543 ce-ai 测嘊 34567 测伌") (write-file file)) (pyim-import-words-and-counts file (lambda (orig-count new-count) new-count) t) ;; 测试词条是否存在 (dolist (x '("测㤅" "测嘊" "测伌")) (should (member x (pyim-dcache-get "ce-ai" '(icode2word))))) (should (equal (gethash "测㤅" pyim-dhashcache-iword2count) 76543)) (should (equal (gethash "测嘊" pyim-dhashcache-iword2count) 34567)) (should (equal (gethash "测伌" pyim-dhashcache-iword2count) 0))))) ;; ** pyim-dcache 相关单元测试 (ert-deftest pyim-tests-pyim-dcache-backend () (let ((pyim-dcache-backend 'pyim-dregcache) (pyim-default-scheme 'quanpin)) (should (eq (pyim-dcache-backend) 'pyim-dregcache))) (let ((pyim-dcache-backend 'pyim-dregcache) (pyim-default-scheme 'wubi)) (should (eq (pyim-dcache-backend) 'pyim-dhashcache))) (let ((pyim-dcache-backend 'pyim-dhashcache1)) (should (eq (pyim-dcache-backend) 'pyim-dhashcache)))) (ert-deftest pyim-tests-pyim-dcache-save/read-variable-value () (let* ((file (pyim-tests-make-temp-file)) (backup-file (concat file "-backup-" (format-time-string "%Y%m%d%H%M%S"))) (value (make-hash-table :test #'equal))) (puthash "ni-hao" (list "你好") value) (pyim-dcache-save-value-to-file value file) (should (equal (gethash "ni-hao" (pyim-dcache-get-value-from-file file)) '("你好"))) (should-not (file-exists-p backup-file)) (pyim-dcache-save-value-to-file "" file 0.8) (should (file-exists-p backup-file)) (should (equal (gethash "ni-hao" (pyim-dcache-get-value-from-file backup-file)) '("你好"))))) (ert-deftest pyim-tests-pyim-dcache-handle-variable () (let ((pyim-dcache-directory (pyim-tests-make-temp-file t)) my/test:1) (pyim-dcache-save-variable 'my/test:1 "hello") (should (equal (pyim-dcache-get-value 'my/test:1) "hello")) (setq my/test:1 "hi") (pyim-dcache-reload-variable my/test:1) (should (equal my/test:1 "hello")) (setq my/test:1 "hi") (pyim-dcache-init-variable my/test:1) (should (equal my/test:1 "hi")) (setq my/test:1 nil) (pyim-dcache-init-variable my/test:1) (should (equal my/test:1 "hello")))) (ert-deftest pyim-tests-pyim-dcache-export () (let ((pyim-dcache-backend 'pyim-dhashcache) (pyim-dhashcache-iword2count (make-hash-table :test #'equal)) (pyim-dhashcache-icode2word (make-hash-table :test #'equal)) (file (pyim-tests-make-temp-file))) (puthash "你好" 10 pyim-dhashcache-iword2count) (puthash "锕系" 10 pyim-dhashcache-iword2count) (puthash "尼耗" 1 pyim-dhashcache-iword2count) (puthash "wo-hao" (list "我好") pyim-dhashcache-icode2word) (puthash "ni-hao" (list "你好" "尼耗") pyim-dhashcache-icode2word) (pyim-dcache-export-words-and-counts file) (with-temp-buffer (insert-file-contents file) (should (equal (buffer-string) ";;; -*- coding: utf-8-unix -*- 锕系 10 尼耗 1 你好 10 我好 0 "))) (pyim-dcache-export-words-and-counts file nil t) (with-temp-buffer (insert-file-contents file) (should (equal (buffer-string) ";;; -*- coding: utf-8-unix -*- 锕系 尼耗 你好 我好 "))) (pyim-dcache-export-personal-words file) (with-temp-buffer (insert-file-contents file) (should (equal (buffer-string) ";;; -*- coding: utf-8-unix -*- ni-hao 你好 尼耗 wo-hao 我好 "))))) (ert-deftest pyim-tests-pyim-dcache-insert-word () (let ((pyim-dcache-backend 'pyim-dhashcache) (pyim-dhashcache-icode2word (make-hash-table :test #'equal))) (pyim-dcache-insert-word "你好" "ni-hao" t) (pyim-dcache-insert-word "尼耗" "ni-hao" t) (pyim-dcache-insert-word "呢耗" "ni-hao" nil) (pyim-dcache-insert-word (propertize "你豪" :noexport t) "ni-hao" nil) (should (equal (gethash "ni-hao" pyim-dhashcache-icode2word) '("尼耗" "你好" "呢耗" #("你豪" 0 2 (:noexport t))))) (should (get-text-property 0 :noexport (nth 3 (gethash "ni-hao" pyim-dhashcache-icode2word)))) (pyim-dcache-insert-word "你豪" "ni-hao" nil) (should-not (get-text-property 0 :noexport (nth 3 (gethash "ni-hao" pyim-dhashcache-icode2word)))))) (ert-deftest pyim-tests-pyim-dcache-update-wordcount () (let ((pyim-dcache-backend 'pyim-dhashcache) (pyim-dhashcache-iword2count (make-hash-table :test #'equal))) (pyim-dcache-update-wordcount "你好") (should (equal (gethash "你好" pyim-dhashcache-iword2count) 0)) (pyim-dcache-update-wordcount "你好" (lambda (n) (+ n 3))) (should (equal (gethash "你好" pyim-dhashcache-iword2count) 3)) (pyim-dcache-update-wordcount "你好" #'1+) (should (equal (gethash "你好" pyim-dhashcache-iword2count) 4)) (pyim-dcache-update-wordcount "你好" 10) (should (equal (gethash "你好" pyim-dhashcache-iword2count) 10)) (pyim-dcache-update-wordcount "你好" nil) (should (equal (gethash "你好" pyim-dhashcache-iword2count) 10)) (pyim-dcache-update-wordcount "你好" "xxx") (should (equal (gethash "你好" pyim-dhashcache-iword2count) 10)))) ;; ** pyim-dict 相关单元测试 (ert-deftest pyim-tests-pyim-dict () (let ((pyim-extra-dicts nil) (dict1 '(:name "test1" :file "/home/user/test1.pyim")) (dict2 '(:name "test2" :file "/home/user/test2.pyim")) (dict3 '(:name "test1" :file "/home/user/test3.pyim")) (dict4 '(:name "test4" :file "/home/user/test4.pyim" :disable t))) (pyim-extra-dicts-add-dict dict1) (should (equal pyim-extra-dicts `(,dict1))) (pyim-extra-dicts-add-dict dict2) (should (equal pyim-extra-dicts `(,dict1 ,dict2))) (pyim-extra-dicts-add-dict dict3) (should (equal pyim-extra-dicts `(,dict3 ,dict2))) (pyim-extra-dicts-add-dict dict4) (should (equal (pyim-dict-get-enabled-dict-files) '("/home/user/test3.pyim" "/home/user/test2.pyim"))))) ;; ** pyim-dhashcache 相关单元测试 (ert-deftest pyim-tests-pyim-dhashcache--pinyin-string< () (should (pyim-dhashcache--pinyin-string< "啊" "波")) (should-not (string< "锕" "波")) (should (pyim-dhashcache--pinyin-string< "锕" "波")) (should-not (pyim-dhashcache--pinyin-string< "波" "啊")) (should (pyim-dhashcache--pinyin-string< "a" "b")) (should-not (pyim-dhashcache--pinyin-string< "b" "a")) (should (pyim-dhashcache--pinyin-string< "aa" "ab")) (should-not (pyim-dhashcache--pinyin-string< "ab" "aa")) (should (pyim-dhashcache--pinyin-string< "你不好" "你好")) (should-not (pyim-dhashcache--pinyin-string< "你好" "你不好")) ) (ert-deftest pyim-tests-pyim-dhashcache--get-ishortcodes-shortcodes () (should (equal (pyim-dhashcache--get-ishortcodes-shortcodes ".abcde") nil)) (should (equal (pyim-dhashcache--get-ishortcodes-shortcodes "wubi/abcde") '("wubi/abcd" "wubi/abc" "wubi/ab"))) (should (equal (pyim-dhashcache--get-ishortcodes-shortcodes "abcde") nil)) (should (equal (pyim-dhashcache--get-ishortcodes-shortcodes "ni-hao") nil)) (should (equal (pyim-dhashcache--get-ishortcodes-shortcodes "") nil))) (ert-deftest pyim-tests-pyim-dhashcache--get-ishortcodes-ishortcodes () (should (equal (pyim-dhashcache--get-ishortcodes-ishortcodes "ni--hao--") '("n-h"))) (should (equal (pyim-dhashcache--get-ishortcodes-ishortcodes "ni--hao") '("n-h"))) (should (equal (pyim-dhashcache--get-ishortcodes-ishortcodes "ni-hao") '("n-h"))) (should (equal (pyim-dhashcache--get-ishortcodes-ishortcodes "wubi/aaaa") nil)) (should (equal (pyim-dhashcache--get-ishortcodes-ishortcodes "ni") '("n"))) (should (equal (pyim-dhashcache--get-ishortcodes-ishortcodes "") nil))) (ert-deftest pyim-tests-pyim-dhashcache--get-ishortcodes-path () (let* ((dir (pyim-tests-make-temp-file t)) (pyim-dcache-directory dir)) (should (equal (pyim-dhashcache--get-ishortcodes-path 'hello) (expand-file-name "hello" dir))) (should (equal (pyim-dhashcache--get-ishortcodes-path "hello") nil)))) (ert-deftest pyim-tests-pyim-dhashcache--generate-file () (let ((dist-file (pyim-tests-make-temp-file)) (dcache-file (pyim-tests-make-temp-file)) (word2code-dcache-file (pyim-tests-make-temp-file)) output1 output2) (with-temp-buffer (insert ";; -*- coding: utf-8 -*-- a 阿 啊 呵 腌 吖 嗄 锕 錒 pinyin/a 阿 啊 呵 腌 吖 嗄 锕 錒 a-a 啊啊 wo 我 zuo-zuo-ye 做作业 zuo-zuo-you-mang 作作有芒") (write-region (point-min) (point-max) dist-file)) (pyim-dhashcache--generate-dcache-file (list dist-file) dcache-file) (with-temp-buffer (insert-file-contents dcache-file) (setq output1 (read (current-buffer))) (pyim-dhashcache--generate-word2code-dcache-file output1 word2code-dcache-file)) (with-temp-buffer (insert-file-contents word2code-dcache-file) (setq output2 (read (current-buffer)))) (should (equal (gethash "a" output1) '("阿" "啊" "呵" "腌" "吖" "嗄" "锕" "錒"))) (should (equal (gethash "a-a" output1) '("啊啊"))) (should (equal (gethash "zuo-zuo-you-mang" output1) '("作作有芒"))) (should (equal (gethash "啊" output2) '("pinyin/a"))) (should (equal (gethash "我" output2) nil)) (should (equal (gethash "啊啊" output2) nil)))) (ert-deftest pyim-tests-pyim-dhashcache--update-shortcode2word () (let ((pyim-dhashcache-iword2count (make-hash-table :test #'equal)) (code2word (make-hash-table :test #'equal)) (shortcode2word (make-hash-table :test #'equal)) output) (puthash "wubi/a" '("戈") code2word) (puthash "wubi/aa" '("式" "藏") code2word) (puthash "wubi/aaa" '("工") code2word) (puthash "wubi/aaaa" '("工" "㠭") code2word) (puthash "wubi/aaab" '("㐂") code2word) (puthash "wubi/aaae" '("𧝣") code2word) (setq shortcode2word (pyim-dhashcache--update-shortcode2word-1 code2word)) (should (equal (gethash "wubi/aa" shortcode2word) '(#("工" 0 1 (:comment "a")) #("㠭" 0 1 (:comment "aa")) #("㐂" 0 1 (:comment "ab")) #("𧝣" 0 1 (:comment "ae"))))) (should (equal (gethash "wubi/aaa" shortcode2word) '(#("工" 0 1 (:comment "a")) #("㠭" 0 1 (:comment "a")) #("㐂" 0 1 (:comment "b")) #("𧝣" 0 1 (:comment "e"))))))) (ert-deftest pyim-tests-pyim-dhashcache--update-ishortcode2word () (let ((pyim-dhashcache-iword2count (make-hash-table :test #'equal)) (icode2word (make-hash-table :test #'equal)) ishortcode2word) (puthash "ni" '("你" "呢") icode2word) (puthash "ni-hao" '("你好" "呢耗") icode2word) (puthash "ni-huai" '("你坏") icode2word) (setq ishortcode2word (pyim-dhashcache--update-ishortcode2word-1 icode2word)) (should (equal (gethash "n-h" ishortcode2word) '("你好" "呢耗" "你坏"))) (should (equal (gethash "n" ishortcode2word) '("你" "呢"))))) (ert-deftest pyim-tests-pyim-dhashcache--put/delete () (let ((pyim-dcache-backend 'pyim-dhashcache) (pyim-dhashcache-icode2word (make-hash-table :test #'equal))) (puthash "ni-hao" '("你好" "呢耗") pyim-dhashcache-icode2word) (pyim-dhashcache--put pyim-dhashcache-icode2word "ni-hao" (cons "呢毫" orig-value)) (pyim-dhashcache--put pyim-dhashcache-icode2word "ni-bu-hao" (list "你不好")) (should (equal (gethash "ni-hao" pyim-dhashcache-icode2word) '("呢毫" "你好" "呢耗"))) (should (equal (gethash "ni-bu-hao" pyim-dhashcache-icode2word) '("你不好"))) (pyim-dcache-delete-word "你不好") (should (equal (gethash "ni-bu-hao" pyim-dhashcache-icode2word) nil)) (pyim-dcache-delete-word "你好") (should (equal (gethash "ni-hao" pyim-dhashcache-icode2word) '("呢毫" "呢耗"))))) (ert-deftest pyim-tests-pyim-dhashcache--update-iword2count () (let ((pyim-dhashcache-iword2count (make-hash-table :test #'equal))) (puthash "你好" 1 pyim-dhashcache-iword2count) (pyim-dhashcache--update-iword2count "你好") (should (equal (gethash "你好" pyim-dhashcache-iword2count) 1)) (pyim-dhashcache--update-iword2count "你好" #'1+) (should (equal (gethash "你好" pyim-dhashcache-iword2count) 2)) (pyim-dhashcache--update-iword2count "你好" 10) (should (equal (gethash "你好" pyim-dhashcache-iword2count) 10)) (pyim-dhashcache--update-iword2count "你好" (lambda (x) (* x 2))) (should (equal (gethash "你好" pyim-dhashcache-iword2count) 20)))) (ert-deftest pyim-tests-pyim-dhashcache--export () (let ((file (pyim-tests-make-temp-file)) (icode2word (make-hash-table :test #'equal))) (puthash "yin-xing" (list (propertize "银行" :noexport t) "因行") icode2word) (pyim-dhashcache--export icode2word file) (with-temp-buffer (insert-file-contents file) (should (equal(buffer-string) ";;; -*- coding: utf-8-unix -*- yin-xing 因行 "))))) (ert-deftest pyim-tests-pyim-dhashcache--get-ishortcodes () (let ((pyim-dcache-backend 'pyim-dhashcache) (pyim-dhashcache-code2word (make-hash-table :test #'equal)) (pyim-dhashcache-icode2word (make-hash-table :test #'equal)) (pyim-dhashcache-iword2count (make-hash-table :test #'equal))) (puthash "ni-hao" '("呢耗") pyim-dhashcache-icode2word) (puthash "ni-hao" '("你好") pyim-dhashcache-code2word) (puthash "你好" 10 pyim-dhashcache-iword2count) (should (equal (pyim-dcache-get "ni-hao" '(code2word)) '("你好"))) (should (equal (pyim-dcache-get "ni-hao" '(icode2word)) '("呢耗"))) (should (equal (pyim-dcache-get "你好" '(iword2count)) '(10))) (should (equal (pyim-dcache-get "ni-hao" '(code2word icode2word)) '("你好" "呢耗"))) (should (equal (pyim-dcache-get "ni-hao") '("呢耗" "你好"))))) (ert-deftest pyim-tests-pyim-dhashcache--insert-word-into-icode2word () (let ((pyim-dhashcache-icode2word (make-hash-table :test #'equal))) (pyim-dhashcache--insert-word-into-icode2word "你好" "ni-hao" t) (pyim-dhashcache--insert-word-into-icode2word "你耗" "ni-hao" t) (pyim-dhashcache--insert-word-into-icode2word "你豪" "ni-hao" nil) (should (equal (gethash "ni-hao" pyim-dhashcache-icode2word) '("你耗" "你好" "你豪"))))) (ert-deftest pyim-tests-pyim-dhashcache--insert-word-into-ishortcode2word () (let ((pyim-dhashcache-ishortcode2word (make-hash-table :test #'equal))) (pyim-dhashcache--insert-word-into-ishortcode2word "你好" "ni-hao" t) (pyim-dhashcache--insert-word-into-ishortcode2word "你慌" "ni-huang" t) (pyim-dhashcache--insert-word-into-ishortcode2word "你坏" "ni-huai" nil) (should (equal (gethash "n-h" pyim-dhashcache-ishortcode2word) '("你慌" "你好" "你坏"))))) (ert-deftest pyim-tests-pyim-dcache-sort-words () (let ((pyim-dcache-backend 'pyim-dhashcache) (pyim-dhashcache-iword2count (make-hash-table :test #'equal)) words) (puthash "你好" 3 pyim-dhashcache-iword2count) (puthash "呢耗" 2 pyim-dhashcache-iword2count) (puthash "你豪" 1 pyim-dhashcache-iword2count) (setq words (list "呢耗" "你豪" "你好")) (should (equal (pyim-dcache-sort-words words) '("你好" "呢耗" "你豪"))))) (ert-deftest pyim-tests-pyim-dhashcache--get-ishortcodes-counts-from-log () (should (member (pyim-dhashcache--get-ishortcodes-counts-from-log '((day :20220107 10 :20220106 6 :20220104 3 :20220103 3)) ;; (date-to-time "2022-01-07") '(25047 4608)) '(((day 6 0 3 3 0 0 0)) ;Fixme: In github-ci will result this value, why? ((day 10 6 0 3 3 0 0)))))) (ert-deftest pyim-tests-pyim-dhashcache--calculate-priority () (should (equal (pyim-dhashcache--calculate-priority '((day 3 7 6 4 5 9 1))) '(69)))) (ert-deftest pyim-tests-pyim-dhashcache--upgrade-icode2word () (should (equal (pyim-dhashcache--upgrade-icode2word-rulers) '(((".") . "wubi/") (("@") . "cangjie/")))) (let ((pyim-dhashcache-icode2word (make-hash-table :test #'equal))) (puthash ".aaaa" '("工") pyim-dhashcache-icode2word) (puthash "wubi/aaaa" '("㠭" "工") pyim-dhashcache-icode2word) (pyim-dhashcache--upgrade-icode2word t) (should-not (gethash ".aaaa" pyim-dhashcache-icode2word)) (should (equal (gethash "wubi/aaaa" pyim-dhashcache-icode2word) '("㠭" "工")))) (let ((pyim-dhashcache-icode2word (make-hash-table :test #'equal))) (puthash ".aaaa" '("工") pyim-dhashcache-icode2word) (puthash "wubi/aaaa" '("㠭" "工") pyim-dhashcache-icode2word) (pyim-dhashcache--upgrade-icode2word) (should (equal (gethash ".aaaa" pyim-dhashcache-icode2word) '("工"))) (should (equal (gethash "wubi/aaaa" pyim-dhashcache-icode2word) '("㠭" "工"))))) ;; ** pyim-dregcache 相关单元测试 (ert-deftest pyim-tests-pyim-general () (let ((pyim-dcache-backend 'pyim-dregcache)) (with-temp-buffer (should (not toggle-input-method-active)) (call-interactively #'toggle-input-method)))) (ert-deftest pyim-tests-pyim-dregcache--backend () (let ((pyim-dcache-backend 'pyim-dregcache) words file-info content) (pyim-dregcache-reset-cache) ;; load dictionary (pyim-dcache-init-variables) (pyim-dcache-update t) ;; cache is filled (should (> (length pyim-dregcache-cache) 0)) ;; get first dictionary cache (setq file-info (plist-get pyim-dregcache-cache (car (pyim-dregcache-cached-dict-files)))) (setq content (plist-get file-info :content)) (let ((i 0) (chars "abcdefghjklmnopqrstwxyz")) (should (eq (length content) (length chars))) (while (< i (length chars)) (should (eq (elt chars i) (elt (nth i content) 0))) (setq i (1+ i)))) (should (string= (pyim-dregcache--get-content "ai" file-info) (pyim-dregcache--get-content "a" file-info))) (should (string= (pyim-dregcache--get-content "ba" file-info) (pyim-dregcache--get-content "b" file-info))) (should (string= (pyim-dregcache--get-content "ze" file-info) (pyim-dregcache--get-content "z" file-info))) ;; test dregcache api (setq words (pyim-dcache-get "a")) (should (eq (length words) 8)) (should (string= (nth 0 words) "阿")) (setq words (pyim-dcache-get "za-cao")) (should (eq (length words) 1)) (should (string= (nth 0 words) "杂草")) (setq words (pyim-dcache-get "ba-shi-tian-huan-you-di-qiu")) (should (eq (length words) 1)) (should (string= (nth 0 words) "八十天环游地球")) (setq words (pyim-dcache-get "zun-bei")) (should (eq (length words) 1)) (should (string= (nth 0 words) "尊卑")) (setq words (pyim-dcache-get "zun")) (should (string= (nth 0 words) "尊")) (let* ((gc-cons-threshold most-positive-fixnum)) (message "search by code \"zun-yi\" takes %s seconds" (benchmark-run-compiled 1 (pyim-dcache-get "zun-yi")))) ;; `pyim-dregcache--get' calls `pyim-pymap-py2cchar-get' before return result (should (eq (length words) 26)))) ;; ** pyim-cloudim 相关单元测试 (ert-deftest pyim-tests-pyim-cloudim () (with-temp-buffer (insert "HTTP/1.1 200 OK Content-Length: 88 Content-Type: text/plain; charset=utf-8 Date: Sun, 08 May 2022 00:56:13 GMT {\"0\":[[[\"嘻嘻\",4,{\"pinyin\":\"xi'xi\",\"type\":\"IMEDICT\"}],[\"茜茜\",8,{\"pinyin\":\"qian'qian\",\"type\":\"IMEDICT\"}],[\"洗洗\",4,{\"pinyin\":\"xi'xi\",\"type\":\"IMEDICT\"}]]],\"1\":\"xi'xi\",\"result\":[null]}") (should (equal (pyim-cloudim--parse-baidu-buffer) '("嘻嘻" "茜茜" "洗洗"))) (should (equal (get-text-property 0 :comment (car (pyim-cloudim--parse-baidu-buffer))) "(云)"))) (should (equal (pyim-cloudim--parse-baidu-buffer-string "{\"0\":[[[\"嘻嘻\",4,{\"pinyin\":\"xi'xi\",\"type\":\"IMEDICT\"}],[\"茜茜\",8,{\"pinyin\":\"qian'qian\",\"type\":\"IMEDICT\"}],[\"洗洗\",4,{\"pinyin\":\"xi'xi\",\"type\":\"IMEDICT\"}]]],\"1\":\"xi'xi\",\"result\":[null]}") '("嘻嘻" "茜茜" "洗洗"))) (with-temp-buffer (insert "HTTP/1.1 200 OK Date: Sun, 08 May 2022 03:33:56 GMT Pragma: no-cache Expires: -1 Cache-Control: no-cache, must-revalidate Cross-Origin-Resource-Policy: cross-origin Content-Type: application/json; charset=UTF-8 X-Content-Type-Options: nosniff Content-Disposition: attachment; filename=\"f.txt\" Server: Google Input Server/1.0 X-XSS-Protection: 0 X-Frame-Options: SAMEORIGIN Alt-Svc: h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\" Transfer-Encoding: chunked [\"SUCCESS\",[[\"nihao\",[\"你好\"],[],{\"annotation\":[\"ni hao\"],\"candidate_type\":[0],\"lc\":[\"16 16\"]}]]]") (should (equal (pyim-cloudim--parse-google-buffer) '("你好"))) (should (equal (get-text-property 0 :comment (car (pyim-cloudim--parse-google-buffer))) "(云)")))) ;; ** pyim-probe 相关单元测试 (ert-deftest pyim-tests-pyim-probe-program-mode () (with-temp-buffer (emacs-lisp-mode) (insert ";; comment") (should-not (pyim-probe-program-mode)) (insert "\n") (should (pyim-probe-program-mode)) (insert "()") (backward-char 1) (should (pyim-probe-program-mode)) (insert "setq test") (should (pyim-probe-program-mode)) (insert " \"\"") (backward-char 1) (should-not (pyim-probe-program-mode)))) (ert-deftest pyim-tests-pyim-probe-isearch-mode () ;; Isearch mode 不好写测试,这里假设 isearch 命令运行时,至少有一个 buffer 中 ;; 变量 isearch-mode 取值为 t. 参考了 `isearch-define-mode-toggle'. (let ((pyim-isearch-mode t)) (with-current-buffer (get-buffer-create "test") (setq-local isearch-mode t)) (should (pyim-probe-isearch-mode)))) (ert-deftest pyim-tests-pyim-probe-org-speed-commands () (with-temp-buffer (let ((org-use-speed-commands t)) (org-mode) (insert "* heading") (goto-char (line-beginning-position)) (should (pyim-probe-org-speed-commands)) (forward-char 1) (should-not (pyim-probe-org-speed-commands)) (forward-char 1) (should-not (pyim-probe-org-speed-commands))))) (ert-deftest pyim-tests-pyim-probe-org-structure-template () (with-temp-buffer (org-mode) (insert "<") (should (pyim-probe-org-structure-template)) (insert "abcde") (should (pyim-probe-org-structure-template)) (insert " ") (should-not (pyim-probe-org-structure-template)) (erase-buffer) (insert " <") (should (pyim-probe-org-structure-template)) (insert "abcde") (should (pyim-probe-org-structure-template)) (insert " ") (should-not (pyim-probe-org-structure-template)))) (ert-deftest pyim-tests-pyim-probe-dynamic-english () (with-temp-buffer ;; 从光标往前找第一个非数字的字符,为其他字符时,输入下一个字符时默认开启英文输入 (insert "english") (should (pyim-probe-dynamic-english)) (insert "123") (should (pyim-probe-dynamic-english)) (insert ",") (should (pyim-probe-dynamic-english)) (insert " ") (should (pyim-probe-dynamic-english)) ;; 从光标往前找第一个非数字的字符,为中文字符时,输入下一个字符时默认开启中文输入 (insert "中文") (should-not (pyim-probe-dynamic-english)))) (ert-deftest pyim-tests-pyim-probe-auto-english () (with-temp-buffer ;; 1. 当前字符为英文字符(不包括空格)时,输入下一个字符为英文字符 (insert "english") (should (pyim-probe-auto-english)) ;; 当前字符为中文字符或输入字符为行首字符时,输入的字符为中文字符 (insert "\n") (should-not (pyim-probe-auto-english)) (insert "中文") (should-not (pyim-probe-auto-english)) ;; 以单个空格为界,自动切换中文和英文字符 (insert " ") (should (pyim-probe-auto-english)) (insert "english ") (should-not (pyim-probe-auto-english)) (insert "中文 ") (should (pyim-probe-auto-english)))) (ert-deftest pyim-tests-pyim-probe-evil-normal-mode () (when (featurep 'evil) (with-temp-buffer (evil-local-mode) (should (pyim-probe-evil-normal-mode)) (evil-local-mode -1) (should-not (pyim-probe-evil-normal-mode))))) (ert-deftest pyim-tests-pyim-probe-punctuation-line-beginning () (with-temp-buffer (should (pyim-probe-punctuation-line-beginning ?.)) (insert "fff") (should-not (pyim-probe-punctuation-line-beginning ?.)) (insert "\n") (should (pyim-probe-punctuation-line-beginning ?.)))) (ert-deftest pyim-tests-pyim-probe-punctuation-after-punctuation () (with-temp-buffer (should-not (pyim-probe-punctuation-after-punctuation ?.)) (insert "'") (should (pyim-probe-punctuation-after-punctuation ?.)) (insert "abc") (should-not (pyim-probe-punctuation-after-punctuation ?.)) (insert "123") (should-not (pyim-probe-punctuation-after-punctuation ?.)) (insert "。") (should-not (pyim-probe-punctuation-after-punctuation ?.)) (insert ".") (should (pyim-probe-punctuation-after-punctuation ?.)))) (ert-deftest pyim-tests-pyim-probe-org-latex-mode () (with-temp-buffer (org-mode) (insert "\\begin{equation}") (save-excursion (insert "\\end{equation}")) (should (pyim-probe-org-latex-mode)) (erase-buffer) (insert "$$") (backward-char 1) (should (pyim-probe-org-latex-mode)) (erase-buffer) (insert "\\documentclass{article}") (should (pyim-probe-org-latex-mode)))) (ert-deftest pyim-tests-pyim-probe-exwm-xim-environment () (with-temp-buffer (setq-local exwm-xim-buffer-p t) (should (pyim-probe-exwm-xim-environment)) (setq-local exwm-xim-buffer-p nil) (should-not (pyim-probe-exwm-xim-environment)))) (ert-deftest pyim-tests-pyim-probe-xwidget-webkit-environment () ;; TODO ) ;; ** pyim-page 相关单元测试 (ert-deftest pyim-tests-pyim-page--start () (let ((pyim-process--candidates '("你" "妮" "拟" "你" "尼" "呢" "泥" "妮" "拟" "逆" "倪")) (pyim-page-length 3)) (should (equal (pyim-page--start 2) 0)) (should (equal (pyim-page--start 7) 6)) (should (equal (pyim-page--start 6) 6)) (should (equal (pyim-page--start 5) 3)))) (ert-deftest pyim-tests-pyim-page--end () (let ((pyim-process--candidates '("你" "妮" "拟" "你" "尼" "呢" "泥" "妮" "拟" "逆" "倪")) (pyim-page-length 3)) (let ((pyim-process--word-position 0)) (should (eq (pyim-page--end) 3))) (let ((pyim-process--word-position 1)) (should (eq (pyim-page--end) 3))) (let ((pyim-process--word-position 1)) (should (eq (pyim-page--end) 3))) (let ((pyim-process--word-position 2)) (should (eq (pyim-page--end) 3))) (let ((pyim-process--word-position 3)) (should (eq (pyim-page--end) 6))) (let ((pyim-process--word-position 9)) (should (eq (pyim-page--end) 11))))) (ert-deftest pyim-tests-pyim-page--current-page () (let ((pyim-process--candidates '("你" "妮" "拟" "你" "尼" "呢" "泥" "妮" "拟" "逆" "倪")) (pyim-page-length 3)) (let ((pyim-process--word-position 0)) (should (equal (pyim-page--current-page) 1))) (let ((pyim-process--word-position 2)) (should (equal (pyim-page--current-page) 1))) (let ((pyim-process--word-position 3)) (should (equal (pyim-page--current-page) 2))))) (ert-deftest pyim-tests-pyim-page--total-page () (let ((pyim-process--candidates '("你" "妮" "拟" "你" "尼" "呢" "泥" "妮" "拟" "逆" "倪")) (pyim-page-length 3)) (should (equal (pyim-page--total-page) 4))) (let ((pyim-process--candidates '("你" "妮" "拟" "你" "尼" "呢" "泥" "妮" "拟")) (pyim-page-length 3)) (should (equal (pyim-page--total-page) 3)))) (ert-deftest pyim-tests-pyim-page--add-default-page-face () (let ((string (pyim-page--add-default-page-face (concat "aaa\n" (propertize "bbb\n" 'face 'pyim-page-select-word) "ccc")))) (should (equal (get-text-property 0 'face string) 'pyim-page)) (should (equal (get-text-property 1 'face string) 'pyim-page)) (should (equal (get-text-property 10 'face string) 'pyim-page)) (should (equal (get-text-property 4 'face string) '(pyim-page-select-word pyim-page))))) (ert-deftest pyim-tests-pyim-page--align-lines () (should (equal (pyim-page--align-lines "你好 abc 这是") "你好 abc 这是"))) (ert-deftest pyim-tests-pyim-page--tooltip-valid-p () (let ((pyim-page-tooltip-infos `((posframe1 :package posframe1) (posframe2 :package posframe :test (lambda () t)) (posframe3 :package posframe :test (lambda () nil))))) (should-not (pyim-page--tooltip-valid-p 'posframe1)) (should (pyim-page--tooltip-valid-p 'posframe2)) (should-not (pyim-page--tooltip-valid-p 'posframe3)))) (ert-deftest pyim-tests-pyim-page--get-page-style () (let ((pyim-page-tooltip-style-alist '((minibuffer . minibuffer))) (pyim-page-style 'test)) (should (equal (pyim-page--get-page-style 'minibuffer) 'minibuffer)) (should (equal (pyim-page--get-page-style 'test) 'test)))) (ert-deftest pyim-tests-pyim-page-info-format () (let ((page-info (list :scheme (pyim-scheme-get 'quanpin) :current-page 1 :total-page 26 :candidates '("你好" "尼耗" "您耗" "您好" "你") :position 2 :hightlight-current 'hightlight-current :assistant-enable nil))) (should (equal (pyim-page-info-format 'two-lines page-info) "=> | [1/26]: 1.你好 2.尼耗 3[您耗]4.您好 5.你 ")) (should (equal (pyim-page-info-format 'no-exist-style page-info) "=> | [1/26]: 1.你好 2.尼耗 3[您耗]4.您好 5.你 ")) (should (equal (pyim-page-info-format 'one-line page-info) "[|]: 1.你好 2.尼耗 3[您耗]4.您好 5.你 (1/26)")) (should (equal (pyim-page-info-format 'vertical page-info) "=> | [1/26]: 1.你好 2.尼耗 3[您耗] 4.您好 5.你 ")) (should (equal (pyim-page-info-format 'minibuffer page-info) "[| ]: 1.你好 2.尼耗 3[您耗]4.您好 5.你 (1/26) $ ")))) (ert-deftest pyim-tests-pyim-page-menu-create () (should (equal (pyim-page-menu-create '("你好" "尼耗" "您耗" "您好" "你") 0 nil t) #("1[你好]2.尼耗 3.您耗 4.您好 5.你 " 1 5 (face pyim-page-selection)))) (should (equal (pyim-page-menu-create '("你好" "尼耗" "您耗" "您好" "你") 1 nil t) #("1.你好 2[尼耗]3.您耗 4.您好 5.你 " 6 10 (face pyim-page-selection)))) (should (equal (pyim-page-menu-create '("你好" "尼耗" "您耗" "您好" "你") 2 nil t) #("1.你好 2.尼耗 3[您耗]4.您好 5.你 " 11 15 (face pyim-page-selection))))) ;; ** pyim-preview 相关单元测试 (ert-deftest pyim-tests-pyim-preview-string () (let ((pyim-process--candidates '("世界" "时节" "使节" "视界" )) (pyim-process--word-position 0) (pyim-outcome--history '("你好")) (pyim-process--imobjs '((("sh" "i" "sh" "i") ("j" "ie" "j" "ie")))) (scheme (pyim-scheme-get 'quanpin))) (should (equal (pyim-preview-string scheme) "你好世界"))) (let ((pyim-process--candidates '("世界" "时节" "使节" "视界" )) (pyim-process--word-position 1) (pyim-outcome--history nil) (pyim-process--imobjs '((("sh" "i" "sh" "i") ("j" "ie" "j" "ie")))) (scheme (pyim-scheme-get 'quanpin))) (should (equal (pyim-preview-string scheme) "时节"))) (let ((pyim-process--candidates '("这是" "蛰是" "这时" "真实" "这使" "这事" "这" "者" "着" "折" "哲" "浙" "遮")) (pyim-process--word-position 9) (pyim-outcome--history nil) (pyim-process--imobjs '((("zh" "e" "zh" "e") ("sh" "i" "sh" "i")))) (scheme (pyim-scheme-get 'quanpin))) (should (equal (pyim-preview-string scheme) "折shi"))) (let ((pyim-process--candidates '("工" "藏匿" "工工" "花花草草" "㠭")) (pyim-process--word-position 3) (pyim-outcome--history nil) (pyim-process--imobjs '(("aaaa"))) (scheme (pyim-scheme-get 'wubi))) (should (equal (pyim-preview-string scheme) "花花草草")))) ;; ** pyim-autoselecter 相关单元测试 (ert-deftest pyim-tests-pyim-autoselecter--xingma () (should-not (apply #'pyim-autoselector--xingma '(4 "aaaa" ("工" "藏匿" "花花草草" "工工" "㠭") ("工")))) (should (equal (apply #'pyim-autoselector--xingma '(4 "aaaab" ("工" "藏匿" "花花草草" "工工" "㠭") ("工"))) '(:select last))) ;; 自动清除错误输入模式,类似微软五笔:敲第五个字母的时候,前面四个字母自动清除 (should (equal (apply #'pyim-autoselector--xingma '(4 "xxxxa" ("工" "戈") ("xxxx"))) '(:select last :replace-with ""))) (should (equal (apply #'pyim-autoselector--xingma '(4 "aaaa" ("工") ("工"))) '(:select current)))) ;; ** pyim-process 相关单元测试 (ert-deftest pyim-tests-pyim-process-ui-init () (let* ((pyim-test nil) (pyim-process-ui-init-hook (list (lambda () (setq pyim-test 'hello))))) (pyim-process-ui-init) (should (equal pyim-test 'hello)))) (ert-deftest pyim-tests-pyim-process-start-daemon () (let* ((pyim-test nil) (pyim-process-start-daemon-hook (list (lambda () (setq pyim-test 'hello))))) (pyim-process-start-daemon) (should (equal pyim-test 'hello)))) (ert-deftest pyim-tests-pyim-process-stop-daemon () (let* ((pyim-test nil) (pyim-process-stop-daemon-hook (list (lambda () (setq pyim-test 'hello))))) (pyim-process-stop-daemon) (should (equal pyim-test 'hello)))) (ert-deftest pyim-tests-pyim-process-auto-switch-english-input-p () (let ((pyim-english-input-switch-functions (list (lambda () t) (lambda () nil) (lambda () nil)))) (should (pyim-process-auto-switch-english-input-p))) (let ((pyim-english-input-switch-functions (list (lambda () t) (lambda () t) (lambda () nil)))) (should (pyim-process-auto-switch-english-input-p))) (let ((pyim-english-input-switch-functions (list (lambda () nil) (lambda () nil) (lambda () nil)))) (should-not (pyim-process-auto-switch-english-input-p))) (let ((pyim-english-input-switch-functions nil)) (should-not (pyim-process-auto-switch-english-input-p))) (let ((pyim-english-input-switch-functions (lambda () nil))) (should-not (pyim-process-auto-switch-english-input-p))) (let ((pyim-english-input-switch-functions (lambda () t))) (should (pyim-process-auto-switch-english-input-p))) (let ((pyim-english-input-switch-functions "xxx")) (should-not (pyim-process-auto-switch-english-input-p)))) (ert-deftest pyim-tests-pyim-process--force-input-chinese-p () (let ((pyim-process--force-input-chinese nil) (pyim-force-input-chinese-functions (list (lambda () t) (lambda () nil) (lambda () nil)))) (should (pyim-process--force-input-chinese-p))) (let ((pyim-process--force-input-chinese nil) (pyim-force-input-chinese-functions (list (lambda () t) (lambda () t) (lambda () nil)))) (should (pyim-process--force-input-chinese-p))) (let ((pyim-process--force-input-chinese nil) (pyim-force-input-chinese-functions (lambda () t))) (should (pyim-process--force-input-chinese-p))) (let ((pyim-process--force-input-chinese nil) (pyim-force-input-chinese-functions (lambda () nil))) (should-not (pyim-process--force-input-chinese-p))) (let ((pyim-process--force-input-chinese nil) (pyim-force-input-chinese-functions "xxx")) (should-not (pyim-process--force-input-chinese-p))) (let ((pyim-process--force-input-chinese nil) (pyim-force-input-chinese-functions (list (lambda () nil) (lambda () nil) (lambda () nil)))) (should-not (pyim-process--force-input-chinese-p))) (let ((pyim-process--force-input-chinese t) (pyim-force-input-chinese-functions nil)) (should (pyim-process--force-input-chinese-p))) (let ((pyim-process--force-input-chinese t) (pyim-force-input-chinese-functions (list (lambda () nil) (lambda () nil) (lambda () nil)))) (should (pyim-process--force-input-chinese-p)))) (ert-deftest pyim-tests-pyim-process--input-chinese-predicate-1 () (cl-letf (((symbol-function 'pyim-process--force-input-chinese-p) (lambda () t)) (pyim-process--input-ascii t) ((symbol-function 'pyim-process-auto-switch-english-input-p) (lambda () t))) (should (pyim-process--input-chinese-predicate-1))) (cl-letf (((symbol-function 'pyim-process--force-input-chinese-p) (lambda () t)) (pyim-process--input-ascii nil) ((symbol-function 'pyim-process-auto-switch-english-input-p) (lambda () t))) (should (pyim-process--input-chinese-predicate-1))) (cl-letf (((symbol-function 'pyim-process--force-input-chinese-p) (lambda () t)) (pyim-process--input-ascii nil) ((symbol-function 'pyim-process-auto-switch-english-input-p) (lambda () t))) (should (pyim-process--input-chinese-predicate-1))) (cl-letf (((symbol-function 'pyim-process--force-input-chinese-p) (lambda () nil)) (pyim-process--input-ascii nil) ((symbol-function 'pyim-process-auto-switch-english-input-p) (lambda () nil))) (should (pyim-process--input-chinese-predicate-1))) (cl-letf (((symbol-function 'pyim-process--force-input-chinese-p) (lambda () nil)) (pyim-process--input-ascii t) ((symbol-function 'pyim-process-auto-switch-english-input-p) (lambda () nil))) (should-not (pyim-process--input-chinese-predicate-1))) (cl-letf (((symbol-function 'pyim-process--force-input-chinese-p) (lambda () nil)) (pyim-process--input-ascii nil) ((symbol-function 'pyim-process-auto-switch-english-input-p) (lambda () t))) (should-not (pyim-process--input-chinese-predicate-1))) (cl-letf (((symbol-function 'pyim-process--force-input-chinese-p) (lambda () nil)) (pyim-process--input-ascii nil) ((symbol-function 'pyim-process-auto-switch-english-input-p) (lambda () nil))) (should (pyim-process--input-chinese-predicate-1)))) (ert-deftest pyim-tests-pyim-process--input-chinese-predicate-2 () (should (pyim-process--input-chinese-predicate-2 ?a "" "abc" "def")) (should-not (pyim-process--input-chinese-predicate-2 ?d "" "abc" "def")) (should (pyim-process--input-chinese-predicate-2 ?d "a" "abc" "def")) (should-not (pyim-process--input-chinese-predicate-2 ?g "a" "abc" "def"))) (ert-deftest pyim-tests-pyim-process-input-chinese-p () (cl-letf (((symbol-function 'pyim-process--input-chinese-predicate-1) (lambda (&rest _) nil)) ((symbol-function 'pyim-process--input-chinese-predicate-2) (lambda (&rest _) nil))) (should-not (pyim-process-input-chinese-p))) (cl-letf (((symbol-function 'pyim-process--input-chinese-predicate-1) (lambda (&rest _) t)) ((symbol-function 'pyim-process--input-chinese-predicate-2) (lambda (&rest _) nil))) (should-not (pyim-process-input-chinese-p))) (cl-letf (((symbol-function 'pyim-process--input-chinese-predicate-1) (lambda (&rest _) nil)) ((symbol-function 'pyim-process--input-chinese-predicate-2) (lambda (&rest _) t))) (should-not (pyim-process-input-chinese-p))) (cl-letf (((symbol-function 'pyim-process--input-chinese-predicate-1) (lambda (&rest _) t)) ((symbol-function 'pyim-process--input-chinese-predicate-2) (lambda (&rest _) t))) (should (pyim-process-input-chinese-p)))) (ert-deftest pyim-tests-pyim-process-autoselector () (let* ((pyim-process-autoselector (list (lambda () (list :select 'current :replace "test1")) (lambda () (list :select 'current :replace "test1")) (lambda () (list :select 'current :replace "test2")) (lambda () (list :select 'current :replace "test2")) (lambda () (list :select 'last :replace "test3")) (lambda () (list :select 'last :replace "test3")) (lambda () (list :select 'last :replace "test4")) (lambda () (list :select 'last :replace "test4")))) (results (pyim-process--autoselector-results))) (should (equal results '((:select current :replace "test1") (:select current :replace "test2") (:select last :replace "test3") (:select last :replace "test4")))) (should (equal (pyim-process--autoselector-find-result results 'current) '(:select current :replace "test1"))) (should (equal (pyim-process--autoselector-find-result results 'last) '(:select last :replace "test3"))))) (ert-deftest pyim-tests-pyim-process-self-insert-command-p () (let ((pyim-process--self-insert-commands nil)) (cl-pushnew 'test pyim-process--self-insert-commands) (should (pyim-process-self-insert-command-p 'test)))) (ert-deftest pyim-tests-pyim-process-ui-refresh () (let* ((result1 nil) (result2 nil) (pyim-process-ui-refresh-hook (list (lambda (x) (setq result1 "result1")) (lambda (x) (setq result2 "result2"))))) (pyim-process-ui-refresh) (should (equal result1 "result1")) (should (equal result2 "result2")))) (ert-deftest pyim-tests-pyim-process--merge-candidates () (should (equal (pyim-process--merge-candidates '("a" "b" "c") '("d" "e" "f" "a" "b")) '("d" "a" "b" "c" "e" "f")))) (ert-deftest pyim-tests-pyim-process-word-position () (let ((pyim-process--candidates '("你" "妮" "拟" "你" "尼" "呢" "泥" "妮" "拟" "逆" "倪"))) (let ((pyim-process--word-position 3)) (should (equal (pyim-process-word-position) 3))) (let ((pyim-process--word-position 10)) (should (equal (pyim-process-word-position) 10))) (let ((pyim-process--word-position 11)) (should (equal (pyim-process-word-position) 10))) (should (equal (pyim-process-word-position 0) 0)) (should (equal (pyim-process-word-position 10) 10)) (should (equal (pyim-process-word-position 11) 10)))) (ert-deftest pyim-tests-pyim-process-next-word-position () (let ((pyim-process--candidates '("你" "妮" "拟" "你" "尼" "呢" "泥" "妮" "拟" "逆" "倪")) ;;; 0 1 2 3 4 5 6 7 8 9 10 (pyim-process--word-position 3)) (should (equal (pyim-process-next-word-position 1) 4)) (should (equal (pyim-process-next-word-position 7) 10)) (should (equal (pyim-process-next-word-position 8) 0)) (should (equal (pyim-process-next-word-position -1) 2)) (should (equal (pyim-process-next-word-position -3) 0)) (should (equal (pyim-process-next-word-position -4) 10)))) (ert-deftest pyim-tests-pyim-process--trigger-delete-word-p () (let ((pyim-default-scheme 'quanpin)) (with-temp-buffer (insert "你好2-") (should (pyim-process--trigger-delete-word-p))))) (ert-deftest pyim-tests-pyim-process--trigger-create-word-p () (let ((pyim-default-scheme 'quanpin)) (with-temp-buffer (insert "你好2") (should (pyim-process--trigger-create-word-p))))) (ert-deftest pyim-tests-pyim-process--trigger-call-function-p () (let ((pyim-default-scheme 'quanpin)) (with-temp-buffer (insert "你好") (should (pyim-process--trigger-call-function-p))) (with-temp-buffer (insert "你好,") (should-not (pyim-process--trigger-call-function-p))))) (ert-deftest pyim-tests-pyim-process--trigger-punctuation-to-full-width-p () (let ((pyim-default-scheme 'quanpin)) (with-temp-buffer (insert ",") (should (pyim-process--trigger-punctuation-to-full-width-p))))) (ert-deftest pyim-tests-pyim-process--trigger-punctuation-to-half-width-p () (let ((pyim-default-scheme 'quanpin)) (with-temp-buffer (insert ",") (should (pyim-process--trigger-punctuation-to-half-width-p))))) (ert-deftest pyim-tests-pyim-process--find-entered-at-point () (with-temp-buffer (insert "123abc'd ") (should (equal (pyim-process--find-entered-at-point) '("abc'd" 8)))) (with-temp-buffer (insert "123'abcd ") (should (equal (pyim-process--find-entered-at-point) '("abcd" 7))))) (ert-run-tests-batch-and-exit) ;; * Footer ;;; pyim-tests.el ends here pyim-5.3.3/README.org0000644000175000017500000006760514476561504014032 0ustar dogslegdogsleg# Created 2021-04-23 Fri 09:25 #+TITLE: PYIM 是一个 Emacs 中文输入法,支持全拼,双拼,五笔,仓颉 和 Rime 等 #+AUTHOR: Feng Shu #+html: Github Action #+html: GNU ELPA #+html: GNU-devel ELPA #+html: MELPA * 不兼容更新 ** <2022-06-15 Wed> Do not require popup in pyim-page.el popup 是一个非 gnu elpa 包,pyim-page.el 不应该 require 它,需要用户自己手动 require, 使用 popup tooltip 的用户需要在配置中添加: #+begin_src elisp (require 'popup) #+end_src ** <2022-06-13 Mon> pyim-dcache-backend 所需的 package 需要用户手工加载了。 以前 pyim 可以根据 pyim-dcache-backend 的取值自动加载需要的 package, 这样做虽然 方便,但代码特别容易出现问题,考虑到 pyim 未来支持的后端不会有太大变化,我删除了 这个功能,为了向后兼容,pyim 目前会自动加载 pyim-dregcache 包, 但这个兼容代码未 来可能会删除,所以使用 pyim-dregcache 的用户,建议给自己的配置中添加: #+begin_src elisp (require 'pyim-dregcache) #+end_src ** <2022-05-29 Sun> pyim-cregexp-utils, pyim-cstring-utils 和 pyim-dict-manager 需要用户手动 require. 为降低 pyim 代码的复杂度,减少 pyim 依赖包的数量,下面三个包不会自动加载,需要用 户手动 require. 1. pyim-cregexp-utils 2. pyim-cstring-utils 3. pyim-dict-manager (使用 elpa 安装词库,或者手动管理 pyim-dicts 变量的用户不需要这个包) ** <2021-04-28 Wed> 五笔输入法和仓颉输入法的不兼容更新 五笔输入法和仓颉输入法原来使用一个标点符号作为 code-prefix, 现在使用 "wubi/" 和 "cangjie/" 这种形式的 code-prefix, 这样可以减少不同输入法误用同一个 code-prefix 带来的词库冲突。 五笔输入法的 scheme 设置已经移到 pyim-wbdict 包,仓颉输入法的 scheme 设置已经移 到 pyim-cangjie5dict 包。 使用上述两个包的用户,此次变更不受影响,因为两个包使用新的 code-prefix. 受影响的是自己维护五笔和仓颉词库用户,这些用户需要做以下更新: 1. 五笔用户 1. 需要 (require 'pyim-wbdict), 加载五笔 scheme 设置。 2. 需要将自己的五笔词库文件中的 code-prefix "." 替换为 "wubi/". 3. 运行 `pyim-upgrade' 命令,升级 icode2word 词库缓存。 2. 仓颉用户 1. 需要 (require 'pyim-cangjie5dict), 加载仓颉 scheme 设置。 2. 需要将自己的五笔词库文件中的 code-prefix "@" 替换为 "cangjie/". * 截图 [[file:./snapshots/pyim-linux-x-with-toolkit.png]] * 简介 pyim 是 Emacs 环境下的一个中文输入法,最初这个输入法只支持全拼输入,后来根据同学 的提议,添加了五笔等输入法的支持,“pyim” 现在可以理解为: #+begin_center (Peng You input method) #+end_center * 背景 pyim 源于 Emacs-eim。 Emacs-eim 是 Emacs 环境下的一个中文输入法框架, 支持拼音,五笔,仓颉,二笔等多种 输入法,但遗憾的是,2008 年之后它就停止了开发。 虽然外部输入法功能强大,但不能和 Emacs 默契的配合,这一点极大的损害了 Emacs 那种 *行云流水* 的感觉。而本人在使用 Emacs-eim 的过程中发现: 1. *当 Emacs-eim 词库词条很大时,选词频率大大降低,中文体验增强。* 2. *随着使用时间的延长,Emacs-eim 会越来越好用(个人词库的积累)。* 于是我 fork 了 Emacs-eim 输入法的部分代码, 创建了新项目:pyim。 * 目标 pyim 的目标是: *尽最大的努力成为一个好用的 Emacs 中文输入法* , 具体可表现为三个方面: 1. Fallback: 当外部输入法不能使用时,比如在 console 或者 cygwin 环境下,尽最大可 能让 Emacs 用户不必为输入中文而烦恼。 2. Integration: 尽最大可能减少输入法切换频率,让中文输入不影响 Emacs 的体验。 3. Exchange: 尽最大可能简化 pyim 使用其他优秀输入法的词库的难度和复杂度。 * 特点 1. pyim 支持全拼,双拼,五笔和仓颉等输入法,其中对全拼的支持最好。 2. pyim 通过添加词库的方式优化输入法。 3. pyim 使用文本词库格式,方便处理。 4. pyim 可以作为 rime 的前端使用。 * 安装 1. M-x package-install RET pyim RET 2. 在 Emacs 配置文件中(比如: ~/.emacs)添加如下代码: #+begin_example (require 'pyim) (require 'pyim-basedict) ; 拼音词库设置,五笔用户 *不需要* 此行设置 (pyim-basedict-enable) ; 拼音词库,五笔用户 *不需要* 此行设置 (setq default-input-method "pyim") #+end_example * 配置 ** 配置实例 对 pyim 感兴趣的同学,可以看看本人的 pyim 配置,但要注意不要乱抄探针配置。 #+begin_src elisp (require 'pyim) (require 'pyim-basedict) (require 'pyim-cregexp-utils) ;; 如果使用 popup page tooltip, 就需要加载 popup 包。 ;; (require 'popup nil t) ;; (setq pyim-page-tooltip 'popup) ;; 如果使用 pyim-dregcache dcache 后端,就需要加载 pyim-dregcache 包。 ;; (require 'pyim-dregcache) ;; (setq pyim-dcache-backend 'pyim-dregcache) ;; 加载 basedict 拼音词库。 (pyim-basedict-enable) ;; 将 Emacs 默认输入法设置为 pyim. (setq default-input-method "pyim") ;; 显示 5 个候选词。 (setq pyim-page-length 5) ;; 金手指设置,可以将光标处的编码(比如:拼音字符串)转换为中文。 (global-set-key (kbd "M-j") 'pyim-convert-string-at-point) ;; 按 "C-" 将光标前的 regexp 转换为可以搜索中文的 regexp. (define-key minibuffer-local-map (kbd "C-") 'pyim-cregexp-convert-at-point) ;; 设置 pyim 默认使用的输入法策略,我使用全拼。 (pyim-default-scheme 'quanpin) ;; (pyim-default-scheme 'wubi) ;; (pyim-default-scheme 'cangjie) ;; 设置 pyim 是否使用云拼音 ;; (setq pyim-cloudim 'baidu) ;; 设置 pyim 探针 ;; 设置 pyim 探针设置,这是 pyim 高级功能设置,可以实现 *无痛* 中英文切换 :-) ;; 我自己使用的中英文动态切换规则是: ;; 1. 光标只有在注释里面时,才可以输入中文。 ;; 2. 光标前是汉字字符时,才能输入中文。 ;; 3. 使用 M-j 快捷键,强制将光标前的拼音字符串转换为中文。 ;; (setq-default pyim-english-input-switch-functions ;; '(pyim-probe-dynamic-english ;; pyim-probe-isearch-mode ;; pyim-probe-program-mode ;; pyim-probe-org-structure-template)) ;; (setq-default pyim-punctuation-half-width-functions ;; '(pyim-probe-punctuation-line-beginning ;; pyim-probe-punctuation-after-punctuation)) ;; 开启代码搜索中文功能(比如拼音,五笔码等) (pyim-isearch-mode 1) #+end_src ** 添加词库文件 pyim 默认使用 pyim-basedict 词库, 这个词库的词条量8万左右,是一个 *非常小* 的拼 音词库,源于:libpinyin 项目 如果 pyim-basedict 不能满足需求,用户可以使用其他方式为 pyim 添加拼音词库,具体 方式请参考 [[#如何添加自定义拼音词库][如何添加自定义拼音词库]] 小结。 ** 激活 pyim #+begin_example (setq default-input-method "pyim") (global-set-key (kbd "C-\\") 'toggle-input-method) #+end_example * 使用 ** 常用快捷键 | 输入法快捷键 | 功能 | |-----------------------+----------------------------| | C-n 或 M-n 或 + 或 . | 向下翻页 | | C-p 或 M-p 或 - 或 , | 向上翻页 | | C-f | 选择下一个备选词 | | C-b | 选择上一个备选词 | | SPC | 确定输入 | | RET 或 C-m | 字母上屏 | | C-c | 取消输入 | | C-g | 取消输入并保留已输入的中文 | | TAB | 模糊音调整 | | DEL 或 BACKSPACE | 删除最后一个字符 | | C-DEL 或 C-BACKSPACE | 删除最后一个拼音 | | M-DEL 或 M-BACKSPACE | 删除最后一个拼音 | | F1,F2,F3,F4 | 以词定字 | ** 使用云输入法 pyim 可以使用搜索引擎提供的云输入法服务,比如: #+begin_example (setq pyim-cloudim 'baidu) ;; (setq pyim-cloudim 'google) #+end_example ** 使用双拼模式 pyim 支持双拼输入模式,用户可以通过变量 `pyim-default-scheme' 来设定: #+begin_example (pyim-default-scheme 'pyim-shuangpin) #+end_example 注意: 1. pyim 支持微软双拼(microsoft-shuangpin)和小鹤双拼(xiaohe-shuangpin)。 2. 用户可以使用函数 `pyim-scheme-add' 添加自定义双拼方案。 3. 用户可能需要重新设置 `pyim-outcome-trigger'。 ** 使用 rime 输入法 具体安装和使用方式请查看 pyim-liberime 包的 Commentary 部分。 ** 使用型码输入法 1. 五笔输入法可以参考: https://github.com/tumashu/pyim-wbdict 2. 仓颉输入法可以参考:https://github.com/p1uxtar/pyim-cangjiedict 3. 三码郑码(至至郑码)输入法可以参考: https://github.com/p1uxtar/pyim-smzmdict 如果用户在使用型码输入法的过程中,忘记了某个字的编码,可以按 TAB 键临时切换到辅 助输入法来输入,辅助输入法可以通过 `pyim-assistant-scheme' 来设置。 ** 让选词框跟随光标 用户可以通过下面的设置让 pyim 在 *光标处* 显示一个选词框: 1. 使用 popup 或者 popon 包来绘制选词框 (emacs overlay 机制) #+begin_example (require 'popup) (setq pyim-page-tooltip 'popup) #+end_example #+begin_example (require 'popon) (setq pyim-page-tooltip 'popon) #+end_example 2. 使用 posframe 来绘制选词框 #+begin_example (require 'posframe) (setq pyim-page-tooltip 'posframe) #+end_example 注意:pyim 不会自动安装 posframe, 用户需要手动安装这个包, 3. 按照优先顺序自动选择一个可用的 tooltip #+begin_example (setq pyim-page-tooltip '(posframe popup minibuffer)) #+end_example ** 调整 tooltip 选词框的显示样式 pyim 的选词框默认使用 *双行显示* 的样式,在一些特殊的情况下(比如:popup 显示的 菜单错位),用户可以使用 *单行显示*的样式: #+begin_example (setq pyim-page-style 'one-line) #+end_example ** 设置模糊音 可以通过设置 `pyim-pinyin-fuzzy-alist' 变量来自定义模糊音。 ** 使用魔术转换器 用户可以将待选词 “特殊处理” 后再 “上屏”,比如 “简体转繁体” 或者 “输入中文,上屏 英文” 之类的。 用户需要设置 `pyim-outcome-magic-converter', 比如:下面这个例子实现,输入 “二呆”, “一个超级帅的小伙子” 上屏 :-) #+begin_example (defun my-converter (string) (if (equal string "二呆") "“一个超级帅的小伙子”" string)) (setq pyim-outcome-magic-converter #'my-converter) #+end_example ** 切换全角标点与半角标点 1. 第一种方法:使用命令 `pyim-punctuation-toggle',全局切换。这个命令主要用来设 置变量: `pyim-punctuation-translate-p', 用户也可以手动设置这个变量, 比如: #+begin_example (setq-default pyim-punctuation-translate-p '(yes)) ;使用全角标点。 (setq-default pyim-punctuation-translate-p '(no)) ;使用半角标点。 (setq-default pyim-punctuation-translate-p '(auto)) ;中文使用全角标点,英文使用半角标点。 #+end_example 2. 第二种方法:使用命令 `pyim-punctuation-translate-at-point' 只切换光标处标点的 样式。 3. 第三种方法:设置变量 `pyim-outcome-trigger' ,输入变量设定的字符会切换光标处 标点的样式。 ** 手动加词和删词 1. `pyim-convert-string-at-point' 金手指命令,可以比较方便的添加和删除词条,比如: 1. 在 "你好" 后面输入2, 然后运行金手指命令,可以将 “你好” 加入个人词库。 2. 在 “你好” 后面输入2-, 然后运行金手指命令,可以将 “你好” 从个人词库删除。 3. 如果用户选择了一个词条,则运行金手指命令可以将选择的词条加入个人词库。 2. `pyim-create-Ncchar-word-at-point' 这是一组命令,从光标前提取N个汉字字符组成字 符串,并将其加入个人词库。 3. `pyim-outcome-trigger' 以默认设置为例:在 “我爱吃红烧肉” 后输入 “5v”,可以将 “爱吃红烧肉”这个词条保存到用户个人词库。 4. `pyim-create-word-from-selection', 选择一个词条,运行这个命令后,就可以将这个 词条添加到个人词库。 5. `pyim-delete-word' 从个人词库中删除当前高亮选择的词条。 ** pyim 输入状态指示器 pyim 输入状态指示器可以帮助用户快速了解当前 pyim 是处于英文输入状态还是中文输入 状态,因为 pyim probe 探针功能可以让中英文输入状态动态切换,所以快速了解当前中英 文输入状态有时候显得很重要。 pyim 当前内置两种指示器实现方式: 1. 改变光标颜色: pyim-indicator-with-cursor-color, 用户可以使用变量 pyim-indicator-cursor-color 来配置两种输入状态对应的光标颜色。 2. 使用 modeline 显示状态字符串:pyim-indicator-with-mode-line, 用户可以使用变量 pyim-indicator-modeline-string 来配置两种状态对应的显示字符串。 设置默认启用的指示器有两个,用户可以使用下面的变量调整: #+begin_example (setq pyim-indicator-list (list #'pyim-indicator-with-cursor-color #'pyim-indicator-with-modeline)) #+end_example 注意事项: 1. 用户切换 emacs 主题之后,最好重启 pyim 一下。 2. pyim-indicator-with-cursor-color 这个 indicator 很容易和其它设置 cursor 颜色 的包冲突,因为都调用 set-cursor-color,遇到这种情况后,用户需要自己解决冲突, pyim-indicator 提供了一个简单的机制: #+begin_example (setq pyim-indicator-list (list #'my-pyim-indicator-with-cursor-color #'pyim-indicator-with-modeline)) (defun my-pyim-indicator-with-cursor-color (input-method chinese-input-p) (if (not (equal input-method "pyim")) (progn ;; 用户在这里定义 pyim 未激活时的光标颜色设置语句 (set-cursor-color "red")) (if chinese-input-p (progn ;; 用户在这里定义 pyim 输入中文时的光标颜色设置语句 (set-cursor-color "green")) ;; 用户在这里定义 pyim 输入英文时的光标颜色设置语句 (set-cursor-color "blue")))) #+end_example ** pyim 高级功能 1. 根据环境自动切换到英文输入模式,使用 pyim-english-input-switch-functions 配置。 2. 根据环境自动切换到半角标点输入模式,使用 pyim-punctuation-half-width-functions 配置。 3. 如果想在某种环境下强制输入中文,可以使用 pyim-force-input-chinese-functions 来配置,这个设置可以屏蔽掉 pyim-english-input-switch-functions 的设置。 注意:上述两个功能使用不同的变量设置, *千万不要搞错* 。 *** 根据环境自动切换到英文输入模式 | 探针函数 | 功能说明 | |-----------------------------------+-----------------------------------------------------------------------------------| | pyim-probe-program-mode | 如果当前的 mode 衍生自 prog-mode,那么仅仅在字符串和 comment 中开启中文输入模式 | |-----------------------------------+-----------------------------------------------------------------------------------| | pyim-probe-org-speed-commands | 解决 org-speed-commands 与 pyim 冲突问题 | | pyim-probe-isearch-mode | 使用 isearch 搜索时,强制开启英文输入模式 | | | 注意:想要使用这个功能,pyim-isearch-mode 必须激活 | |-----------------------------------+-----------------------------------------------------------------------------------| | pyim-probe-org-structure-template | 使用 org-structure-template 时,关闭中文输入模式 | |-----------------------------------+-----------------------------------------------------------------------------------| | | 1. 当前字符为中文字符时,输入下一个字符时默认开启中文输入 | | pyim-probe-dynamic-english | 2. 当前字符为其他字符时,输入下一个字符时默认开启英文输入 | | | 3. 使用命令 pyim-convert-string-at-point 可以将光标前的拼音字符串强制转换为中文。 | |-----------------------------------+-----------------------------------------------------------------------------------| 激活方式: #+begin_example (setq-default pyim-english-input-switch-functions '(probe-function1 probe-function2 probe-function3)) #+end_example 注意事项: 1. 上述函数列表中,任意一个函数的返回值为 t 时,pyim 切换到英文输入模式。 2. [[https://github.com/DogLooksGood/emacs-rime][Emacs-rime]] 和 [[https://github.com/laishulu/emacs-smart-input-source][smart-input-source]] 也有类似探针的功能,其对应函数可以直接或者简 单包装后作为 pyim 探针使用,有兴趣的同学可以了解一下。 *** 根据环境自动切换到半角标点输入模式 | 探针函数 | 功能说明 | |------------------------------------------+----------------------------| | pyim-probe-punctuation-line-beginning | 行首强制输入半角标点 | |------------------------------------------+----------------------------| | pyim-probe-punctuation-after-punctuation | 半角标点后强制输入半角标点 | |------------------------------------------+----------------------------| 激活方式: #+begin_example (setq-default pyim-punctuation-half-width-functions '(probe-function4 probe-function5 probe-function6)) #+end_example 注:上述函数列表中,任意一个函数的返回值为 t 时,pyim 切换到半角标点输入模式。 * 开发 请参考 [[file:Development.org][Development.org]] 文档 * 试用 在pyim项目根目录运行shell命令 `make runemacs' 试用最新的pyim。 只有pyim和其依赖的包被载入。用户自己的emacs配置不会被载入。 指定运行的Emacs版本用以下命令, #+begin_src sh EMACS=~/my-whatever-directory/bin/emacs make runemacs #+end_src Emacs启动后 "M-x toggle-input-method" 或按 "C-\\" 打开输入法。 * Tips ** pyim 有时候会出现卡顿,如何处理。 可以将云搜词和当前 buffer 搜词功能关闭试试看。 #+begin_example (setq pyim-cloudim nil) (setq pyim-candidates-search-buffer-p nil) #+end_example ** 如何快速切换 scheme 可以试试 pyim-default-scheme 命令。 ** 关闭输入联想词功能 (默认开启) #+begin_example (setq pyim-enable-shortcode nil) #+end_example ** 形码输入法如何微调候选词序 #+begin_example (setq pyim-candidates-xingma-words-function #'my-func) #+end_example ** 如何将个人词条相关信息导入和导出? 1. 导入使用命令: pyim-dcache-import 2. 导出使用命令: pyim-dcache-export ** pyim 出现错误时,如何开启 debug 模式 #+begin_example (setq debug-on-error t) #+end_example ** 将光标处的拼音或者五笔字符串转换为中文 (与 vimim 的 “点石成金” 功能类似) #+begin_example (global-set-key (kbd "M-i") 'pyim-convert-string-at-point) #+end_example ** 如何使用其它字符翻页 #+begin_example (define-key pyim-mode-map "." 'pyim-page-next-page) (define-key pyim-mode-map "," 'pyim-page-previous-page) #+end_example ** 如何用 ";" 来选择第二个候选词 #+begin_example (define-key pyim-mode-map ";" (lambda () (interactive) (pyim-select-word-by-number 2))) #+end_example ** 如何添加自定义拼音词库 pyim 默认没有携带任何拼音词库,用户可以使用下面几种方式,获取质量较好的拼音词库: *** 第一种方式 (Windows 用户推荐使用) 使用词库转换工具将其他输入法的词库转化为 pyim 使用的词库:这里只介绍 windows 平 台下的一个词库转换软件: 1. 软件名称: imewlconverter 2. 中文名称: 深蓝词库转换 3. 下载地址: https://github.com/studyzy/imewlconverter 4. 依赖平台: Microsoft .NET Framework (>= 3.5) 使用方式: [[file:snapshots/imewlconverter-basic.gif]] 如果生成的词库词频不合理,可以按照下面的方式处理(非常有用的功能): [[file:snapshots/imewlconverter-wordfreq.gif]] 生成词库后, #+begin_src emacs-lisp (require 'pyim-dict-manager) #+end_src 然后运行 `pyim-dicts-manager' ,按照命令提示,将转换得到的词库文件的信息添加到 `pyim-dicts' 中,完成后运行命令 `pyim-restart' 或者重启emacs。 *** 第二种方式 (Linux & Unix 用户推荐使用) E-Neo 同学编写了一个词库转换工具: [[https://github.com/E-Neo/scel2pyim][scel2pyim]] , 可以将一个搜狗词库转换为 pyim 词库。 1. 软件名称: scel2pyim 2. 下载地址: https://github.com/E-Neo/scel2pyim 3. 编写语言: C语言 *** 第三种方式 可以了解:https://github.com/redguardtoo/pyim-tsinghua-dict ** 如何手动安装和管理词库 这里假设有两个词库文件: 1. /path/to/pyim-dict1.pyim 2. /path/to/pyim-dict2.pyim 在 ~/.emacs 文件中添加如下一行配置。 #+begin_example (setq pyim-dicts '((:name "dict1" :file "/path/to/pyim-dict1.pyim") (:name "dict2" :file "/path/to/pyim-dict2.pyim"))) #+end_example 注意事项: 1. 只有 :file 是 *必须* 设置的。 2. 必须使用词库文件的绝对路径。 3. 词库文件的编码必须为 utf-8-unix,否则会出现乱码。 ** Emacs 启动时加载 pyim 词库 #+begin_example (add-hook 'emacs-startup-hook (lambda () (pyim-restart-1 t))) #+end_example ** 将汉字字符串转换为拼音字符串 下面两个函数可以将中文字符串转换的拼音字符串或者列表,用于 emacs-lisp 编程。 1. `pyim-cstring-to-pinyin' (尽可能处理多音字,但有可能得到多个拼音) 2. `pyim-cstring-to-pinyin-simple' (尽可能处理多音字,但是只从可能的拼音中获取第一个拼音) ** 中文分词 pyim-cstring-utils 包含了一个简单的分词函数:`pyim-cstring-split-to-list', 可以 将一个中文字符串分成一个词条列表,比如: #+begin_src emacs-lisp :results verbatim (require 'pyim-cstring-utils) (pyim-cstring-split-to-list "我爱北京天安门") #+end_src #+RESULTS: : (("天安" 4 6) ("天安门" 4 7) ("北京" 2 4) ("我爱" 0 2)) 其中,每一个词条列表中包含三个元素,第一个元素为词条本身,第二个元素为词条相对于 字符串的起始位置,第三个元素为词条结束位置。 另一个分词函数是 `pyim-cstring-split-to-string', 这个函数将生成一个新的字符串, 在这个字符串中,词语之间用空格或者用户自定义的分隔符隔开。 注意,上述两个分词函数使用暴力匹配模式来分词,所以,*不能检测出* pyim 词库中不存 在的中文词条。 ** 获取光标处的中文词条 pyim-cstring-utils 包含了一个简单的命令:`pyim-cstring-words-at-point', 这个命令 可以得到光标处的 *英文* 或者 *中文* 词条的 *列表*,这个命令依赖分词函数: `pyim-cstring-split-to-list'。 ** 让 `forward-word' 和 `back-backward’ 在中文环境下正常工作 中文词语没有强制用空格分词,所以 Emacs 内置的命令 `forward-word' 和 `backward-word' 在中文环境不能按用户预期的样子执行,而是 forward/backward “句子” ,pyim自带的两个命令可以在中文环境下正常工作: 1. `pyim-forward-word 2. `pyim-backward-word 用户只需将其绑定到快捷键上就可以了,比如: #+begin_src emacs-lisp (require 'pyim-cstring-utils) (global-set-key (kbd "M-f") 'pyim-forward-word) (global-set-key (kbd "M-b") 'pyim-backward-word) #+end_src ** 为 isearch 相关命令添加拼音搜索支持 pyim 安装后,可以通过下面的设置开启拼音搜索功能: #+begin_src emacs-lisp (require 'pyim-cregexp-utils) (pyim-isearch-mode 1) #+end_src 注意:这个功能有一些限制,搜索字符串中只能出现 “a-z” 和 “'”,如果有其他字符(比 如 regexp 操作符),则自动关闭拼音搜索功能。 开启这个功能后,一些 isearch 扩展有可能失效,如果遇到这种问题, 只能禁用这个 Minor-mode,然后联系 pyim 的维护者,看有没有法子实现兼容。 用户激活这个 mode 后,可以使用下面的方式 *强制关闭* isearch 搜索框中文输入(即使 在 pyim 激活的时候)。 #+begin_example (setq-default pyim-english-input-switch-functions '(pyim-probe-isearch-mode)) #+end_example ** 创建一个搜索中文的 regexp #+begin_src emacs-lisp (pyim-cregexp-build ".*nihao.*") #+end_src #+RESULTS: : \(?:.*\(?:nihao\|[㒟㖏㖕㖖㖻㘈㘝㘨㘿㙞㚔㜤㜦㜵㜸㝕㞋㞙㞾㟧㠜㠡㡪㣇㣷㤛㥾㦐㧱㩘㩶㪒㭤㮆㮏㮞㮟㲡㲰㲻㲽㳮㴪㵫㸎㹸㺲㼭㽱㿦䀑䀔䁥䂇䂼䃵䄒䄭䄹䆨䇣䋴䋻䌜䌰䍲䏔䐁䒜䔭䕥䖆䗿䘌䘦䘽䙚䚓䚾䛏䛘䜆䜓䝚䞕䟢䡾䤔䦊䦵䧇䧔䩞䬯䭃䭢䭲䮍䮗䮘䯀䯅䯵䰯䳖䴴䵑䵒乜伱伲佞你侫倪儗儜儞兒凝匿卄呢咛唸啮喦嗫噛嚀嚙囁囐囓囜圼坭埝埿堄妞妮妳姩娘婗嫋嫟嬝嬢嬣嬲嬺孃孨孴孼孽宁寍寕寗寜寧尼尿屔屰峊嵲嶭巕帇年廿念忸怓怩恁您惄惗愵慝懝扭抐抝抳拈拗拟拧拰捏捻掜揑摂摄摰撚撵擜擬擰攆敜旎昵晲暱杻枿柅柠棿榐槷樢橣檷檸櫱氼氽汼沑泞泥涅涊淣淰湼溓溺濘炄牛牜狃狋狔狞猊獰甯疌疒痆眤睨矃碾祢禰秊秜秥篞簐籋籾粘糱糵紐縌纽聂聍聶聹聻胒脲腝腻膩臡臬臲艌苧苨苶茑茮莥菍蔦蔫薴薿蘖蘗蚭蚴蛪蜺蠥衂衵袅裊褭褹觬誽諗譺讘貎跈跜踂踗蹍蹑蹨躎躡輗輦輾辇辗迡逆郳酿醸釀鈕鈢鈮鉨鉩銸鋷錜鎳鑈鑏鑷钀钮铌镊镍闑陧隉隬霓靵顳颞馜鬡鬤鮎鯓鯢鯰鲇鲵鲶鳥鶂鷊鸋鸟鸮鹝鹢麑黏鼰齞齧齯][㕺㘪㙱㚪㝀㞻㠙㩝㬔㬶㵆䒵䚽䝞䝥䧚䧫䪽䬉䯫侾傐儫勂号呺哠嗥嘷噑嚆嚎壕好峼恏悎昊昦晧暠暤暭曍椃毫浩淏滈澔濠瀥灏灝狢獆獋獔皓皜皞皡皥秏竓籇耗聕茠蒿薃薅薧藃號虠蚝蠔諕譹诐豪貉郝鄗鎬镐顥颢鰝鶴鸮]\).*\) ** 让 ivy 支持拼音搜索候选项功能 #+begin_src emacs-lisp (require 'pyim-cregexp-utils) (setq ivy-re-builders-alist '((t . pyim-cregexp-ivy))) #+end_src ** 让 avy 支持拼音搜索 #+begin_src emacs-lisp (with-eval-after-load 'avy (defun my-avy--regex-candidates (fun regex &optional beg end pred group) (let ((regex (pyim-cregexp-build regex))) (funcall fun regex beg end pred group))) (advice-add 'avy--regex-candidates :around #'my-avy--regex-candidates)) #+end_src ** 让 vertico, selectrum 等补全框架,通过 orderless 支持拼音搜索候选项功能。 #+begin_src emacs-lisp (defun my-orderless-regexp (orig-func component) (let ((result (funcall orig-func component))) (pyim-cregexp-build result))) (advice-add 'orderless-regexp :around #'my-orderless-regexp) #+end_src pyim-5.3.3/pyim-liberime.el0000644000175000017500000003105214360477013015426 0ustar dogslegdogsleg;;; pyim-liberime.el --- Rime support for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Version: 3.2 ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;; * pyim-liberime 使用说明 :README:doc: ;; 1. 安裝配置 liberime 和 pyim, 方式见:[[https://github.com/merrickluo/liberime][liberime]]. ;; 2. 使用 rime 全拼输入法的用户,也可以使用 rime-quanpin scheme, ;; 这个 scheme 是专门针对 rime 全拼输入法定制的,支持全拼v快捷键。 ;; #+BEGIN_EXAMPLE ;; (require 'liberime) ;; (require 'pyim-liberime) ;; (setq pyim-default-scheme 'rime-quanpin) ;; #+END_EXAMPLE ;; 3. 如果通过 rime 使用微软双拼,可以用以下设置: ;; #+BEGIN_EXAMPLE ;; (liberime-select-schema "double_pinyin_mspy") ;; (setq pyim-default-scheme 'rime-microsoft-shuangpin) ;; #+END_EXAMPLE ;; 默认是用繁体中文,想要改成简体中文的话,可以参考 [[https://github.com/rime/home/wiki/CustomizationGuide#%E4%B8%80%E4%BE%8B%E5%AE%9A%E8%A3%BD%E7%B0%A1%E5%8C%96%E5%AD%97%E8%BC%B8%E5%87%BA][rime wiki]],或者[[http://wenshanren.org/?p=1070#orgc7dbd8e][这篇博客]] ;;; Code: ;; * 代码 :code: (require 'pyim) (cl-defstruct (pyim-scheme-rime (:include pyim-scheme) (:constructor pyim-scheme-rime-create) (:copier nil)) "Rime 输入法方案。" code-split-length code-maximum-length) (pyim-scheme-add '(rime :document "rime 输入法。 这个 scheme 适用于 librime 支持的所有输入法,通用性较好,但无法支 持 trigger, 所以类似 pyim 全拼支持的v快捷键将无法使用。" :class rime :code-prefix "rime/" :code-prefix-history ("&") :first-chars "abcdefghijklmnopqrstuvwxyz" :rest-chars "abcdefghijklmnopqrstuvwxyz'-a" :prefer-triggers nil :cregexp-support-p nil)) (pyim-scheme-add '(rime-quanpin :document "rime 全拼输入法。 这个 scheme 专门用于 librime 全拼输入法,同时支持 trigger, 也就是 v 快捷键,使用 rime 全拼的朋友建议使用这个 scheme。" :class rime :code-prefix "rime/" :code-prefix-history ("&") :first-chars "abcdefghjklmnopqrstwxyz" :rest-chars "vmpfwckzyjqdltxuognbhsrei'-a" :prefer-triggers ("v"))) (pyim-scheme-add '(rime-microsoft-shuangpin :document "rime 微软双拼输入法。" :class rime :code-prefix "rime/" :code-prefix-history ("&") :first-chars "abcdefghijklmnopqrstuvwxyz" :rest-chars "abcdefghijklmnopqrstuvwxyz;" :prefer-triggers nil)) (declare-function liberime-get-commit "liberime") (declare-function liberime-get-context "liberime") (declare-function liberime-clear-commit "liberime") (declare-function liberime-clear-composition "liberime") (declare-function liberime-search "liberime" (string limit)) (declare-function liberime-get-preedit "liberime") (declare-function liberime-get-status "liberime") (declare-function liberime-process-key "liberime" (keycode &optional mask)) (declare-function liberime-select-candidate "liberime" (num)) (defun pyim-liberime--scheme (orig_func) "Advice function of `pyim-scheme-current'." (let ((scheme (funcall orig_func))) (if (pyim-scheme-rime-p scheme) (if (featurep 'liberime-core) scheme (pyim-scheme-get 'quanpin)) scheme))) (advice-add 'pyim-scheme-current :around #'pyim-liberime--scheme) (cl-defmethod pyim-imobjs-create (entered (_scheme pyim-scheme-rime)) (list (list entered))) (cl-defmethod pyim-codes-create (imobj (scheme pyim-scheme-rime) &optional first-n) (when scheme (let ((code-prefix (pyim-scheme-code-prefix scheme))) (mapcar (lambda (x) (concat (or code-prefix "") (if (numberp first-n) (substring x 0 (min first-n (length x))) x))) imobj)))) (cl-defmethod pyim-candidates-create (imobjs (scheme pyim-scheme-rime)) "适用于 rime 的 `pyim-candidates-create' 方法。" (let* ((code (car (pyim-codes-create (car imobjs) scheme))) (code-prefix (pyim-scheme-code-prefix scheme)) (s (replace-regexp-in-string "-" "" code)) ;; `liberime-search' 搜索的时候不需要 code-prefix, 去除。 (s (if code-prefix (string-remove-prefix code-prefix s) s)) (words (liberime-search s (* pyim-page-length 2)))) words)) (cl-defmethod pyim-candidates-create-limit-time (imobjs (scheme pyim-scheme-rime)) "适用于 rime 的 `pyim-candidates-create-limit-time' 方法。" (let* ((code (car (pyim-codes-create (car imobjs) scheme))) (code-prefix (pyim-scheme-code-prefix scheme)) (s (replace-regexp-in-string "-" "" code)) ;; `liberime-search' 搜索的时候不需要 code-prefix, 去除。 (s (if code-prefix (string-remove-prefix code-prefix s) s)) (words (liberime-search s nil))) words)) (defun pyim-autoselector-rime (&rest _args) "适用于RIME的自动上屏器." (let* ((scheme (pyim-scheme-current))) (when (pyim-scheme-rime-p scheme) (let* ((commit (liberime-get-commit)) (context (liberime-get-context)) (composition (alist-get 'composition context)) (length (alist-get 'length composition))) (cond ;; 有新输入的顶屏模式 ((and commit (eq length 1)) `(:select last :replace-with ,commit)) ;; 无新输入的顶屏模式 (commit `(:select current :replace-with ,commit)) (t nil)))))) (add-to-list 'pyim-process-autoselector 'pyim-autoselector-rime) (cl-defmethod pyim-page-preview-create ((_scheme pyim-scheme-rime) &optional separator) (let* ((preedit (or (liberime-get-preedit) (pyim-entered-get 'point-before)))) (pyim-process-with-entered-buffer (if (equal 1 (point)) (concat "|" preedit) (concat (replace-regexp-in-string (concat separator "'") "'" preedit) " |" (buffer-substring-no-properties (point) (point-max))))))) (defvar pyim-liberime-code-log nil) (defvar pyim-liberime-word-log nil) (cl-defmethod pyim-process-select-word ((_scheme pyim-scheme-rime)) "从选词框中选择当前词条,然后删除该词条对应拼音。" (pyim-process-select-word-without-save 'do-not-terminate) (let* ((entered (pyim-entered-get 'point-before)) (word (pyim-outcome-diff)) (code (pyim-liberime--get-code word entered)) (to-be-translated (string-remove-prefix code entered))) (push code pyim-liberime-code-log) (push word pyim-liberime-word-log) (if (or (> (length to-be-translated) 0) ;是否有光标前未转换的字符串 (> (length (pyim-entered-get 'point-after)) 0)) ;是否有光标后字符串 (progn (pyim-process-with-entered-buffer (delete-region (point-min) (point)) (insert to-be-translated) (goto-char (point-max))) (pyim-process-run)) ;; 在 rime 后端造词和调整词频 (pyim-liberime--create-word (reverse pyim-liberime-code-log) (reverse pyim-liberime-word-log)) ;; 使用 rime 的同时,也附带的优化 quanpin 的词库。 (let ((pyim-default-scheme 'quanpin)) (if (member (pyim-outcome-get) (pyim-process-get-candidates)) (pyim-process-create-word (pyim-outcome-get) t) (pyim-process-create-word (pyim-outcome-get)))) (setq pyim-liberime-code-log nil) (setq pyim-liberime-word-log nil) (pyim-process-terminate)))) (cl-defmethod pyim-cstring-to-codes (string (_scheme pyim-scheme-rime) &optional criteria) "将中文字符串 STRING 转换为对应的拼音。" (pyim-cstring-to-codes string (pyim-scheme-get 'quanpin) criteria)) (defun pyim-liberime--get-code (word input &optional _limit) "Get the code of WORD from the beginning of INPUT. `liberime-search' with LIMIT argument is used internal. NOTE: This is a hacky approach, the better way is let librime provide an API. Please see: https://github.com/rime/librime/issues/349" (cond ;; 处理基于语音的输入法,比如:拼音,这类输入法 preedit 一般用空格 ;; 分隔,与汉字一一对应。 ((string-match-p (string-join '("pinyin" "luna" "terra" "bopomofo" "stenotype" "jyut6ping3" "wugniu" "soutzoe" "zyenpheng" "sampheng" "clover") "\\|") (alist-get 'schema_id (liberime-get-status))) (unless (liberime-get-preedit) (liberime-search input 1)) (let* ((n (length word)) (preedit (split-string (liberime-get-preedit) "[ ']+")) (preedit-list (cl-subseq preedit 0 (min n (length preedit)))) (i (min (length input) (* n 5))) str) (while (> i 0) (setq str (substring input 0 i)) (liberime-search str 1) (if (equal preedit-list (split-string (liberime-get-preedit) "[ ']+")) (setq i 0) (setq i (- i 1)))) str)) ((string-match-p (string-join '("wubi86" "wubi98") "\\|") (alist-get 'schema_id (liberime-get-status))) (let ((lst (split-string (liberime-get-preedit) "[ ']+")) (str "") words) (while lst (setq str (concat str (pop lst))) (setq words (liberime-search str 20)) (when (member word words) (setq lst nil))) (or str input))) ;; 找不到通用的处理方式的话就不做截取处理。 (t input))) (defun pyim-liberime--create-word (codes words) "通过 CODES 和 WORDS 的信息,在 rime 后端重新造词和调整词频。 比如: 1. CODES -> (\"nihao\" \"ma\") 2. WORDS -> (\"你好\" \"吗\") 在 rime 后端将生成 “你好吗” 这个词条。" (when (and (listp codes) (listp words) (not (cl-find-if-not #'stringp codes)) (not (cl-find-if-not #'stringp words))) (liberime-clear-composition) (dolist (key (string-to-list (string-join codes))) (liberime-process-key key)) (let (word) (while (setq word (pop words)) (let ((status t)) (while status (let* ((context (liberime-get-context)) (menu (alist-get 'menu context)) (last-page-p (alist-get 'last-page-p menu)) (candidates (alist-get 'candidates menu)) (pos (cl-position word candidates :test #'equal))) (cond (pos (liberime-select-candidate pos) (setq status nil)) ((or last-page-p (not menu)) (setq status nil) (setq words nil)) (t (liberime-process-key 65366)))))))))) (defun pyim-liberime-create-word (word &rest _) "将 WORD 添加到 RIME 数据库中。 这个函数仅用于 rime-quanpin scheme." (when-let* ((rime-quanpin-p (equal (pyim-scheme-name (pyim-scheme-current)) 'rime-quanpin)) (chars (remove "" (split-string word ""))) (codes-list (mapcar (lambda (x) (split-string x "-")) (pyim-cstring-to-pinyin word nil "-" t nil t)))) (dolist (codes codes-list) (pyim-liberime--create-word codes chars)) (liberime-clear-commit) (liberime-clear-composition))) (advice-add 'pyim-process-create-word :after #'pyim-liberime-create-word) (cl-defmethod pyim-process-terminate-really ((_scheme pyim-scheme-rime)) (cl-call-next-method) (liberime-clear-commit) (liberime-clear-composition)) ;; * Footer (provide 'pyim-liberime) ;;; pyim-liberime.el ends here pyim-5.3.3/pyim-cregexp.el0000644000175000017500000002634514412763713015307 0ustar dogslegdogsleg;;; pyim-cregexp.el --- Chinese regexp core tools for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-dcache) (require 'pyim-imobjs) (require 'pyim-pymap) (require 'pyim-scheme) (require 'rx) (require 'xr) (defgroup pyim-cregexp nil "Chinese regexp tools for pyim." :group 'pyim) (defcustom pyim-cregexp-fallback-scheme 'quanpin "`pyim-cregexp-build' 使用的 Fallback scheme. 如果 `pyim-cregexp-build' 无法支持用户正在使用的 scheme 时, 将使用这个 scheme." :type 'pyim-scheme) (defun pyim-cregexp-build (string &optional char-level-num chinese-only) "根据 STRING 构建一个中文 regexp. 这个函数的功能和 `pyim-cregexp-build' 类似,大多数参数也相同,不 同点是这个函数没有 scheme 参数,它会根据 `pyim-default-scheme' 和 `pyim-cregexp-fallback-scheme' 等信息动态的获取 scheme." (let ((scheme (pyim-cregexp--scheme))) (pyim-cregexp-create string scheme char-level-num chinese-only))) (defun pyim-cregexp--scheme (&optional scheme) "返回一个支持 cregexp 的 scheme. 这个函数同时考虑 SCHEME, `pyim-default-scheme' 和 `pyim-cregexp-fallback-scheme'." (or (pyim-cregexp--find-scheme scheme) (pyim-cregexp--find-scheme pyim-default-scheme) (pyim-cregexp--find-scheme pyim-cregexp-fallback-scheme) (pyim-cregexp--find-scheme 'quanpin))) (defun pyim-cregexp--find-scheme (scheme-or-name) "如果 SCHEME-OR-NAME 支持 cregexp 功能,就返回对应的 scheme." (let ((scheme (if (pyim-scheme-p scheme-or-name) scheme-or-name (pyim-scheme-get scheme-or-name)))) (when (and (pyim-scheme-p scheme) (pyim-scheme-cregexp-support-p scheme)) scheme))) (defun pyim-cregexp-create (string scheme &optional char-level-num chinese-only) "根据 STRING 构建一个中文 regexp, 用于 \"拼音搜索汉字\". 比如:\"nihao\" -> \"[你呢...][好号...] \\| nihao\" CHAR-LEVEL-NUM 代表汉字常用级别,pyim 中根据汉字的使用频率,将汉 字分为4个级别:1级最常用,4级别最不常用,1-3级汉字大概8000左右, 如果这个参数设置为3, 那么代表在构建 regexp 是,只使用常用级别小于 等于3的汉字。 如果 CHINESE-ONLY 为真,那么生成的 regexp 只能搜索汉字。 注意事项:如果生成的 regexp 太长,Emacs 无法处理,那么,这个命令 会抛弃一些不常用的汉字,重新生成,知道生成一个 Emacs 可以处理的 regexp, 所以搜索单字的时候一般可以搜到生僻字,但搜索句子的时候, 就无法搜索生僻字了。" (if (and string scheme (stringp string) (> (length string) 0) (pyim-scheme-p scheme) (pyim-scheme-cregexp-support-p scheme)) (pyim-cregexp--create-valid-cregexp-from-string string scheme char-level-num chinese-only) string)) (defun pyim-cregexp--create-valid-cregexp-from-string (string scheme &optional char-level-num chinese-only) "从 STRING 创建一个有效的搜索中文的 regexp." (let ((char-level-num (pyim-cregexp--char-level-num char-level-num)) rx-string) (while (and (not (pyim-cregexp--valid-p rx-string)) (> char-level-num 0)) (setq rx-string (pyim-cregexp--create-beautiful-cregexp-from-string string scheme char-level-num chinese-only)) (setq char-level-num (1- char-level-num))) rx-string)) (defun pyim-cregexp--char-level-num (num) "根据 NUM 返回一个有效的常用汉字级别。" (if (numberp num) (max (min num 4) 1) 4)) (defun pyim-cregexp--valid-p (cregexp) "Return t when cregexp is a valid regexp." (and cregexp (stringp cregexp) (not (pyim-cregexp--match-error-p cregexp)))) (defun pyim-cregexp--match-error-p (cregexp) "Return t when an match error is signaled. Emacs can't handle regexps whose length is too big :-(" (equal (condition-case nil (string-match-p cregexp "") (error 'error)) 'error)) (defun pyim-cregexp--create-beautiful-cregexp-from-string (string scheme &optional char-level-num chinese-only) "使用 rx 和 xr, 从 STRING 生成一个漂亮的搜索中文的 regexp. 这个 regexp 可能正常使用,也可能长度超出 emacs 的限制。" (or (ignore-errors (rx-to-string (pyim-cregexp--create-cregexp-from-rx (lambda (x) (if (stringp x) (xr (pyim-cregexp--create-cregexp-from-string x scheme char-level-num chinese-only)) x)) (xr string)))) string)) (defun pyim-cregexp--create-cregexp-from-rx (fn rx-form) (pcase rx-form ('nil nil) (`(,form) (funcall fn form)) (`(any . ,_) rx-form) (`(,_ . ,_) (mapcar (lambda (x) (pyim-cregexp--create-cregexp-from-rx fn x)) rx-form)) (_ (funcall fn rx-form)))) (defun pyim-cregexp--create-cregexp-from-string (string scheme &optional char-level-num chinese-only) (let* ((char-level-num (pyim-cregexp--char-level-num char-level-num)) (string-list (pyim-cregexp--split-string string))) ;; 确保 pyim 词库加载 (pyim-dcache-init-variables) (pyim-cregexp--create-cregexp-from-string-list string-list scheme char-level-num chinese-only))) (defun pyim-cregexp--split-string (string) (let ((sep "#####&&&&#####")) (remove "" (split-string (replace-regexp-in-string "\\([a-z]+'*\\)" (concat sep "\\1" sep) string) sep)))) (defun pyim-cregexp--create-cregexp-from-string-list (string-list scheme &optional char-level-num chinese-only) (mapconcat (lambda (string) (if (or (pyim-string-match-p "[^a-z']+" string) (equal string "")) string (let* ((string1 (replace-regexp-in-string "'" "" string)) (imobjs (pyim-imobjs-create string1 scheme)) (regexp-list (mapcar (lambda (imobj) (pyim-cregexp-create-from-imobj imobj scheme nil nil nil char-level-num)) imobjs)) (regexp (when regexp-list (string-join (delq nil regexp-list) "\\|"))) (regexp (if chinese-only regexp (if (> (length regexp) 0) (if (equal string string1) (concat string "\\|" regexp) (concat string "\\|" string1 "\\|" regexp)) string)))) (format "\\(?:%s\\)" regexp)))) string-list "")) (cl-defgeneric pyim-cregexp-create-from-imobj (imobj _scheme &optional match-beginning first-equal all-equal char-level-num) "从 IMOBJ 创建一个搜索中文的 regexp.") (cl-defmethod pyim-cregexp-create-from-imobj (imobj (_scheme pyim-scheme-quanpin) &optional match-beginning first-equal all-equal char-level-num) "从 IMOBJ 创建一个搜索中文的 regexp, 适用于全拼输入法。" (let* ((num (pyim-cregexp--char-level-num char-level-num)) (pinyin-list (pyim-cregexp--quanpin-get-pinyin-list imobj)) (cchars-list (pyim-cregexp--quanpin-get-cchars-from-pinyin-list pinyin-list all-equal first-equal num)) (regexp (mapconcat (lambda (x) (when (pyim-string-match-p "\\cc" x) (format "[%s]" x))) cchars-list ""))) (unless (equal regexp "") (concat (if match-beginning "^" "") regexp)))) (defun pyim-cregexp--quanpin-get-pinyin-list (imobj) "从 IMOBJ 生成类似 (\"ni\" \"hao\") 的拼音列表。" (mapcar (lambda (x) (concat (nth 0 x) (nth 1 x))) imobj)) (defun pyim-cregexp--quanpin-get-cchars-from-pinyin-list (pinyin-list all-equal first-equal char-level-num) "(\"ni\" \"hao\") => (\"你 ... 蔫 ... 鸟 ... 宁 ...\" \"好号毫\")" (let ((num (pyim-cregexp--char-level-num char-level-num)) (n 0) results) (dolist (py pinyin-list) (let* ((equal-match (or all-equal (and first-equal (= n 0)))) (cchars (mapconcat (lambda (x) (mapconcat #'identity (let* ((list (split-string x "|")) (length (length list))) (cl-subseq list 0 (min num length))) "")) (pyim-pymap-py2cchar-get py equal-match nil t) ""))) (push cchars results)) (setq n (+ 1 n))) (nreverse results))) (cl-defmethod pyim-cregexp-create-from-imobj (imobj (scheme pyim-scheme-xingma) &optional match-beginning first-equal _all-equal _char-level-num) "从 IMOBJ 创建一个搜索中文的 regexp, 适用于形码输入法。" (let* ((code-prefix (pyim-scheme-code-prefix scheme)) (regexp (mapconcat (lambda (x) (let ((code (concat (or code-prefix "") (if first-equal (substring x 0 1) x)))) (pyim-cregexp--build-xingma-regexp-from-words (pyim-dcache-get code '(code2word))))) imobj ""))) (unless (equal regexp "") (concat (if match-beginning "^" "") regexp)))) (defun pyim-cregexp--build-xingma-regexp-from-words (words) "根据 WORDS, 创建一个可以搜索这些 WORDS 的 regexp. 比如:工, 恭恭敬敬 => [工恭][恭]?[敬]?[敬]? 通过 \"[工恭][恭]?[敬]?[敬]?\" 可以搜索 \"工\" 和 \"恭恭敬敬\"." (let ((n (apply #'max (mapcar #'length words))) results) (dotimes (i n) (push (format "[%s]%s" (mapconcat (lambda (x) (if (> i (- (length x) 1)) "" (char-to-string (elt x i)))) words "") (if (> i 0) "?" "")) results)) (string-join (reverse results)))) ;; * Footer (provide 'pyim-cregexp) ;;; pyim-cregexp.el ends here pyim-5.3.3/pyim-cstring.el0000644000175000017500000002426314361742121015311 0ustar dogslegdogsleg;;; pyim-cstring.el --- Chinese string core tools for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-common) (require 'pyim-dcache) (require 'pyim-scheme) (require 'pyim-pymap) (defgroup pyim-cstring nil "Chinese string tools for pyim." :group 'pyim) (defun pyim-cstring--substrings (cstring &optional max-length number) "找出 CSTRING 中所有长度不超过 MAX-LENGTH 的子字符串,生成一个 alist。 这个 alist 中的每个元素为:(子字符串 开始位置 结束位置), 参数 NUMBER 用于递归,表示子字符串在 CSTRING 中的位置。" (let ((number (or number 0))) (cond ((= (length cstring) 0) nil) (t (append (pyim-cstring--substrings-1 cstring max-length number) (pyim-cstring--substrings (substring cstring 1) max-length (1+ number))))))) (defun pyim-cstring--substrings-1 (cstring max-length number) "`pyim-cstring--substrings' 的内部函数。" (cond ((< (length cstring) 2) nil) (t (append (let ((length (length cstring))) (when (<= length (or max-length 6)) (list (list cstring number (+ number length))))) (pyim-cstring--substrings-1 (substring cstring 0 -1) max-length number))))) ;; ** 获取光标处中文字符串 (defun pyim-cstring-at-point (&optional number) "获取光标一个中文字符串,字符数量为:NUMBER." (save-excursion (let* ((point (point)) (begin (- point number)) (begin (if (> begin 0) begin (point-min))) (string (buffer-substring-no-properties point begin))) (when (and (stringp string) (= (length string) number) (not (pyim-string-match-p "\\CC" string))) string)))) ;; ** 中文字符串到拼音的转换工具 ;;;###autoload (defun pyim-cstring-to-pinyin (string &optional shou-zi-mu separator return-list ignore-duo-yin-zi _) "将汉字字符串转换为对应的拼音字符串的工具. 如果 SHOU-ZI-MU 设置为 t, 转换仅得到拼音首字母字符串。当 RETURN-LIST 设置为 t 时,返回一个拼音列表,这个列表包含词条的一个 或者多个拼音(词条包含多音字时);如果 IGNORE-DUO-YIN-ZI 设置为 t, 遇到多音字时,只使用第一个拼音,其它拼音忽略。 BUG: 当 STRING 中包含其它标点符号,并且设置 SEPERATER 时,结果会 包含多余的连接符:比如: \"你=好\" --> \"ni-=-hao\"" (if (not (pyim-string-match-p "\\cc" string)) (if return-list (list string) string) (let* ((pinyins-list (or (pyim-cstring-to-pinyin--from-dcache string) (pyim-pymap-str2py-get string))) (list (mapcar (lambda (x) (mapconcat (lambda (str) (if shou-zi-mu (substring str 0 1) str)) x separator)) (if ignore-duo-yin-zi (list (car pinyins-list)) pinyins-list)))) ;; 返回拼音字符串或者拼音列表 (if return-list list (string-join list " "))))) (defun pyim-cstring-to-pinyin--from-dcache (cstring) "从 Dcache 中搜索 CSTRING 对应的拼音。" (let* ((pinyins-list (mapcar #'pyim-cstring--get-pinyin-code (pyim-pymap-split-string cstring)))) (unless (member nil pinyins-list) (list (apply #'append pinyins-list))))) (defun pyim-cstring--get-pinyin-code (str) "从 Dcache 中获取中文字符串 STR 对应的拼音。 如果 STR 不包含中文,不做特殊处理。" (if (pyim-string-match-p "\\cc" str) (when-let ((code (cl-find-if-not (lambda (c) ;; 注意:Pinyin 词库中不包含 "/" 字符。 (string-match-p c "/")) (pyim-dcache-get str '(word2code))))) (split-string code "-")) (list str))) ;;;###autoload (defun pyim-cstring-to-pinyin-simple (string &optional shou-zi-mu separator return-list) "简化版的 `pyim-cstring-to-pinyin', 不处理多音字。" (pyim-cstring-to-pinyin string shou-zi-mu separator return-list t)) ;; ** 中文字符串到形码的转换工具 (cl-defgeneric pyim-cstring-to-xingma (string scheme &optional return-list) "将中文 STRING 转换为 SCHEME 方案对应的形码。") (cl-defmethod pyim-cstring-to-xingma (string (scheme pyim-scheme-xingma) &optional return-list) "将中文 STRING 转换为 SCHEME 方案对应的形码。 返回的形码不包括 code-prefix。当 RETURN-LIST 设置为 t 时,返回一 个形码 list。" (when (string-match-p "^\\cc+\\'" string) (let* ((prefix (pyim-scheme-code-prefix scheme)) (dcache-codes (mapcar (lambda (x) (when (string-prefix-p prefix x) (string-remove-prefix prefix x))) (sort (cl-copy-list (pyim-dcache-get string '(word2code))) (lambda (a b) (> (length a) (length b)))))) (codes (remove nil dcache-codes))) (when codes (if return-list codes ;; 如果要返回一个字符串,那就返回第一个,也就是最长的那个编码。 (car codes)))))) (cl-defmethod pyim-cstring-to-xingma (string (scheme pyim-scheme-wubi) &optional return-list) "将中文 STRING 转换为五笔编码。 得到的五笔编码包括 code-prefix。当 RETURN-LIST 设置为 t 时,返回 一个五笔编码 list。" (or (cl-call-next-method) (let ((length (length string)) (string (split-string string "" t)) code) (cond ;; 双字词,分别取两个字的前两个编码 ((eq length 2) (let ((s1 (pyim-cstring-to-xingma (nth 0 string) scheme)) (s2 (pyim-cstring-to-xingma (nth 1 string) scheme))) (when (and s1 s2) (setq code (concat (substring s1 0 2) (substring s2 0 2)))))) ;; 三字词,取前二字的首编码,及第三个字的前两个编码 ((eq length 3) (let ((s1 (pyim-cstring-to-xingma (nth 0 string) scheme)) (s2 (pyim-cstring-to-xingma (nth 1 string) scheme)) (s3 (pyim-cstring-to-xingma (nth 2 string) scheme))) (when (and s1 s2 s3) (setq code (concat (substring s1 0 1) (substring s2 0 1) (substring s3 0 2)))))) ;; 四字词及以上,分别前三个字及最后一个字的首编码 ((> length 3) (let ((s1 (pyim-cstring-to-xingma (nth 0 string) scheme)) (s2 (pyim-cstring-to-xingma (nth 1 string) scheme)) (s3 (pyim-cstring-to-xingma (nth 2 string) scheme)) (s4 (pyim-cstring-to-xingma (nth (1- length) string) scheme))) (when (and s1 s2 s3 s4) (setq code (concat (substring s1 0 1) (substring s2 0 1) (substring s3 0 1) (substring s4 0 1)))))) (t nil)) (when code (if return-list (list code) code))))) (cl-defgeneric pyim-cstring-to-codes (string scheme &optional criteria) "将 STRING 转换为 SCHEME 对应的 codes.") (cl-defmethod pyim-cstring-to-codes (string (scheme pyim-scheme-xingma) &optional _) "将中文字符串 STRING 转换为对应的形码." (pyim-cstring-to-xingma string scheme t)) (cl-defmethod pyim-cstring-to-codes (string (_scheme pyim-scheme-quanpin) &optional criteria) "将中文字符串 STRING 转换为对应的拼音。 如果用户提供 CRITERIA 字符串,那么检索到的所有 codes 会和这个字符 串进行字符串相似度比较,然后选择一个相似度最高的 code 作为输出, 这种处理方式适合拼音输入法,形码输入法一般不需要类似的操作。 CRITERIA 字符串一般是通过 imobjs 构建的,它保留了用户原始的输入信 息。" (let ((codes (pyim-cstring-to-pinyin string nil "-" t nil t)) codes-sorted) (if (< (length criteria) 1) codes ;; 将 所有 codes 与 criteria 字符串比对,选取相似度最高的一个 ;; code. 这种处理方式适合拼音输入法。 (setq codes-sorted (sort codes (lambda (a b) (< (pyim-string-distance a criteria) (pyim-string-distance b criteria))))) (list (car codes-sorted))))) ;; PYIM 重构以前使用的一些函数名称,alias 一下,便于兼容。 (defalias 'pyim-hanzi2pinyin-simple #'pyim-cstring-to-pinyin-simple) (defalias 'pyim-hanzi2pinyin #'pyim-cstring-to-pinyin) (defalias 'pyim-hanzi2xingma #'pyim-cstring-to-xingma) ;; * Footer (provide 'pyim-cstring) ;;; pyim-cstring.el ends here pyim-5.3.3/pyim-pinyin.el0000644000175000017500000001612114412763713015147 0ustar dogslegdogsleg;;; pyim-pinyin.el --- pinyin tools for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-pymap) (defgroup pyim-pinyin nil "Pinyin libs for pyim." :group 'pyim) (defcustom pyim-pinyin-fuzzy-alist '(("en" "eng") ("in" "ing") ("un" "ong")) "设定模糊音." :type '(alist :key-type string :value-type (list string))) (defvar pyim-pinyin--shengmu '("b" "p" "m" "f" "d" "t" "n" "l" "g" "k" "h" "j" "q" "x" "z" "c" "s" "zh" "ch" "sh" "r" "y" "w")) (defvar pyim-pinyin--yunmu '("a" "o" "e" "i" "u" "v" "ai" "ei" "ui" "ao" "ou" "iu" "ie" "ia" "ua" "ve" "er" "an" "en" "in" "un" "vn" "ang" "iong" "eng" "ing" "ong" "uan" "uang" "ian" "iang" "iao" "ue" "uai" "uo")) (defvar pyim-pinyin--valid-yunmu '("a" "o" "e" "ai" "ei" "ui" "ao" "ou" "er" "an" "en" "ang" "eng")) (defconst pyim-pinyin--shuangpin-invalid-pinyin-regexp (format "^\\(%s\\)$" (string-join '("[qtghkzcsdn]o" "[ypfbmw]uo" "[qj]ong" "[rtysdghklzcn]iong" "[qtypdjlxbnm]uai" "[ghk]ing?" "[qjlxn]uang" "[dgh]iang" "[qjlx]ua" "[hkg]ia" "[rtsdghkzc]v" "[jl]ui") "\\|")) "双拼可能自动产生的无效拼音. 例如输入 kk 得到有效拼音 kuai . 但同时产生了无效拼音 king . 用户手动输入的无效拼音无需考虑. 因为用户有即时界面反馈,不可能连续输入无效拼音.") ;; 分解拼音的相关函数 (defun pyim-pinyin-split (pinyin) "将一个代表拼音的字符串 PINYIN, 分解为声母韵母对组成的列表. 这个过程通过循环的调用 `pyim-pinyin--get-charpy' 来实现,整个过程 类似用菜刀切黄瓜片,将一个拼音字符串逐渐切开。" (let ((py pinyin) charpy spinyin) (while (when (string< "" pinyin) (setq charpy (pyim-pinyin--get-charpy pinyin)) (if (and (equal (nth 0 (car charpy)) "") (equal (nth 1 (car charpy)) "")) (progn (setq spinyin nil) (setq pinyin "")) (setq spinyin (append spinyin (list (car charpy)))) (setq pinyin (cdr charpy))))) (or spinyin ;; 如果无法按照拼音的规则来分解字符串, ;; 就将字符串简单的包装一下,然后返回。 ;; 目前这个功能用于: 以u或者i开头的词库 #226 ;; https://github.com/tumashu/pyim/issues/226 (list (list "" py "" py))))) (defun pyim-pinyin--get-charpy (pinyin) "将拼音字符串 PINYIN 分解成声母,韵母和剩余部分." (let* ((x (pyim-pinyin--get-shenmu pinyin)) (shenmu (car x)) (yunmu-and-rest (cdr x)) (i (min (length yunmu-and-rest) 5)) yunmu rest) (while (> i 0) (setq yunmu (substring yunmu-and-rest 0 i)) (setq rest (substring yunmu-and-rest i)) (if (member yunmu pyim-pinyin--yunmu) (cond (;; 如果声母和韵母组成的拼音不是一个有效的拼音, ;; 就继续缩短,如果是,就进一步检测。 (not (pyim-pinyin--valid-charpy-p shenmu yunmu)) (setq i (1- i)) (setq yunmu "")) ((and (string< "" rest) ;; 截取后剩余的字符串 rest 找不出声母 (equal (car (pyim-pinyin--get-shenmu rest)) "") ;; 截取后的韵母最后一个字符是一个有效声母 (member (substring yunmu -1) pyim-pinyin--shengmu) ;; 截取得到的韵母如果去掉最后一个字符,还是有效的韵母 (member (substring yunmu 0 -1) pyim-pinyin--yunmu)) (if (not (pyim-pinyin--valid-charpy-p shenmu (substring yunmu 0 -1))) ;; 如果去掉韵母最后一个字符后,无法组成一个有效的拼音。 ;; 就不要缩短了。 (setq i 0) (setq i (1- i)) (setq yunmu ""))) (t (setq i 0))) (setq i (1- i)) (setq yunmu ""))) (cons (list shenmu yunmu shenmu yunmu) (substring yunmu-and-rest (length yunmu))))) (defun pyim-pinyin--get-shenmu (pinyin) "从一个拼音字符串 PINYIN 中提出第一个声母。" (let ((i (min (length pinyin) 2)) shenmu) (while (> i 0) (setq shenmu (substring pinyin 0 i)) (if (member shenmu pyim-pinyin--shengmu) (setq i 0) (setq i (1- i)) (setq shenmu ""))) (cons shenmu (substring pinyin (length shenmu))))) (defun pyim-pinyin--valid-charpy-p (shenmu yunmu) "测试由 SHENMU 和 YUNMU 组成的拼音,是否是一个有效的汉字拼音。 这个函数尊重 `pyim-pinyin-fuzzy-alist' 模糊音设置。" (cl-some (lambda (char-pinyin) (pyim-pymap-py2cchar-get char-pinyin t)) (mapcar (lambda (x) (concat (nth 0 x) (nth 1 x))) (pyim-pinyin-find-fuzzy (list shenmu yunmu shenmu yunmu))))) (defun pyim-pinyin-find-fuzzy (info) "Find all fuzzy pinyins, INFO is (shenmu yunmu shenmu yunmu). (\"f\" \"en\" \"f\" \"en\") -> ((\"f\" \"en\" \"f\" \"en\") (\"f\" \"eng\" \"f\" \"en\"))" (let* ((fuzzy-alist (copy-alist pyim-pinyin-fuzzy-alist)) (sm (nth 0 info)) (ym (nth 1 info)) (sm-list (cl-find-if (lambda (x) (member sm x)) fuzzy-alist)) (ym-list (cl-find-if (lambda (x) (member ym x)) fuzzy-alist)) result) (dolist (a (delete-dups (cons sm sm-list))) (dolist (b (delete-dups (cons ym ym-list))) (push `(,a ,b ,@(nthcdr 2 info)) result))) (reverse result))) (defun pyim-pinyin-valid-shuangpin-p (shuangpin) (not (string-match-p pyim-pinyin--shuangpin-invalid-pinyin-regexp shuangpin))) ;; * Footer (provide 'pyim-pinyin) ;;; pyim-pinyin.el ends here pyim-5.3.3/Development.org0000644000175000017500000000746014244633420015336 0ustar dogslegdogsleg#+TITLE: PYIM 设计开发手册 #+AUTHOR: Feng Shu * 整体架构 #+begin_example +---------------------------------------------------------------------------------------------+ | Emacs IM 接口 PYIM 实现层: | | ------------------------- | | pyim-input-method, pyim-activate, pyim-deactivate | | pyim-exit-from-minibuffer, pyim-mode-map | | +---------------------------------------------------------------------------------+ | | | PYIM 用户命令层: PYIM 视图层: | | | | ---------------- ------------ | | | | Pyim 输入法相关命令 Page | | | | Cregexp-Utils, Cstring-Utils Preview | | | | Pymap-Utils, Dict-Manager Indicator | | | | | | | | +---------------------------------------------+ | | | | 自动上屏器: | PYIM 用例层: Process | | | | | ---------- | | | | | | Autoselector | +-------------------------------+ | | | | | | | PYIM 实体层: | | | | | | | | ----------- | | | | | | | | Entered, Imobjs, Codes, | | | | | | | | Candidates, Outcome, | | | | | | | | Punctuations, Pinyin, | | | | | | | | Cstring, Cregexp, | | | | | | | | Scheme, Assistant-Scheme | | | | | | | +-------------------------------+ | | | | | | | Common, Dcache, Pymap | | | | | | | | | | | | | | | +-------------------------------+ | | | | | | | | | | | | | | | | | +---------------------------------------------+ | | | | | | | | PYIM 持久化层: 云输入法: 探针: | | | | -------------- --------- ------------ | | | | Dregcache Cloudim Probe | | | | Dhashcache | | | | Dict | | | +---------------------------------------------------------------------------------+ | | | +---------------------------------------------------------------------------------------------+ #+end_example pyim-5.3.3/pyim-dhashcache.el0000644000175000017500000010307714361220507015713 0ustar dogslegdogsleg;;; pyim-dhashcache --- uses hash table to cache and search dictionaries -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2015-2020 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;; * 说明文档 :doc: ;; 这个文件为词典建立散列表(Hash Table)结构缓存,提供基于散列表的辞典搜索算法. ;; 搜索速度极快,消耗内存较多. ;; ;; 可以 (setq pyim-dcache-backend 'pyim-dhashcache) 然后重启输入法启用此引擎 ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'async nil t) (require 'pyim-common) (require 'pyim-cstring) (require 'pyim-dcache) (require 'pyim-dict) (require 'pyim-scheme) (require 'pyim-pymap) (require 'sort) (defvar pyim-dhashcache--count-types `((day ;; 保存 day count 时用到的 key 的格式, 类似 :20220206 :format ":%Y%m%d" ;; 在 dcache iword2count-log 中,一个词条最多保存七天的 day count, 这七天可 ;; 能是连续的,也可能不连续。 :max-save-length 7 ;; 计算词条优先级时,连续七天的 day count 对应的权重。 ;; 注意事项:这七个数字的选取,更多的基于猜想和估计,也许有更好的选择。 :weights ,(pyim-proportion (reverse '(1 2 3 5 8 13 21))) ;; 从当天日期获取前一天日期时,需要减去的天数,这个在 day count 类型中没有 ;; 意义,但如果以后添加 month count 类型,这个设置就有意义了。 :delta 1 ;; 计算 day count 对应的优先级数字时,需要乘的一个数,目的是让优先级列表中 ;; 的数字变成合适大小的整数。 :factor ,(/ 100.0 7))) "通过 count 计算词条排序优先级时用到重要信息。 在 pyim 中,优先级表示为数字列表, `pyim-dhashcache--count-types' 每个 count type 对应一个数字。") ;;----------------------------------------- ;; 注意事项: 如果不是迫不得已,不要更改下面几个变量的名称,因为保存词库缓存的时 ;; 候,用到变量的名称,更改之后会出现严重的兼容问题。 (defvar pyim-dhashcache-code2word nil) (defvar pyim-dhashcache-code2word-md5 nil) (defvar pyim-dhashcache-word2code nil) (defvar pyim-dhashcache-iword2count nil) (defvar pyim-dhashcache-iword2count-log nil) (defvar pyim-dhashcache-iword2count-recent-10-words nil) (defvar pyim-dhashcache-iword2count-recent-50-words nil) ;; 注意事项: 在 pyim 中,优先级是多个数字组成的列表,而不是单个数字。 (defvar pyim-dhashcache-iword2priority nil) (defvar pyim-dhashcache-shortcode2word nil) (defvar pyim-dhashcache-icode2word nil) (defvar pyim-dhashcache-ishortcode2word nil) ;; ----------------------------------------- (defvar pyim-dhashcache--update-shortcode2word-p nil) (defvar pyim-dhashcache--update-ishortcode2word-p nil) (defvar pyim-dhashcache--update-icode2word-p nil) (defvar pyim-dhashcache--update-iword2priority-p nil) (defvar pyim-dhashcache--update-code2word-running-p nil) ;; ** 初始化 dhashcache 相关函数 (cl-defmethod pyim-dcache-init-variables (&context ((pyim-dcache-backend) (eql pyim-dhashcache))) "初始化 dcache 缓存相关变量." (when (and (not pyim-dhashcache-icode2word) pyim-dcache-directory (file-directory-p pyim-dcache-directory) (directory-files pyim-dcache-directory nil "-backup-")) (message "PYIM: 在 %S 目录中发现备份文件的存在,可能是词库缓存文件损坏导致,请抓紧检查处理!!!" pyim-dcache-directory)) (pyim-dhashcache--init-count-and-priority-variables) (pyim-dcache-init-variable pyim-dhashcache-code2word) (pyim-dcache-init-variable pyim-dhashcache-word2code) (pyim-dcache-init-variable pyim-dhashcache-shortcode2word) (pyim-dcache-init-variable pyim-dhashcache-icode2word) (pyim-dcache-init-variable pyim-dhashcache-ishortcode2word)) (defun pyim-dhashcache--init-count-and-priority-variables () "初始化 count 相关的变量。" (pyim-dcache-init-variable pyim-dhashcache-iword2count) (pyim-dcache-init-variable pyim-dhashcache-iword2count-log) (pyim-dcache-init-variable pyim-dhashcache-iword2count-recent-10-words) (pyim-dcache-init-variable pyim-dhashcache-iword2count-recent-50-words) (pyim-dcache-init-variable pyim-dhashcache-iword2priority)) ;; ** 从 dhashcache 搜索词条相关函数 (cl-defmethod pyim-dcache-get (key &context ((pyim-dcache-backend) (eql pyim-dhashcache)) &optional from) "从 FROM 中搜索 key, 得到对应的结果。 用于 pyim-dhashcache 类型的 dcache 后端。" (when key (let* ((caches (mapcar (lambda (x) (intern (concat "pyim-dhashcache-" (symbol-name x)))) (or (and from (if (listp from) from (list from))) '(icode2word code2word)))) result) (dolist (cache caches) (let* ((cache (ignore-errors (symbol-value cache))) (value (and cache (gethash key cache)))) ;; 处理 iword2count. (unless (listp value) (setq value (list value))) (when value (setq result (append result value))))) result))) ;; ** 给 dhashcache 添加词条相关函数 (cl-defmethod pyim-dcache-insert-word (word code prepend &context ((pyim-dcache-backend) (eql pyim-dhashcache))) "将词条 WORD 插入到下面两个词库缓存中。 1. `pyim-dhashcache-icode2word' 2. `pyim-dhashcache--insert-word-into-ishortcode2word'." (pyim-dhashcache--insert-word-into-icode2word word code prepend) ;; NOTE: 保存词条到 icode2word 词库缓存的同时,也在 ishortcode2word 词库缓存中 ;; 临时写入一份,供当前 Emacs session 使用,但退出时 pyim 不会保存 ;; ishortcode2word 词库缓存到文件,因为下次启动 Emacs 的时候,ishortcode2word ;; 词库缓存会从 icode2word 再次重建。 (pyim-dhashcache--insert-word-into-ishortcode2word word code prepend)) (defmacro pyim-dhashcache--put (cache code &rest body) "将 BODY 的返回值保存到 CACHE 对应的 CODE 中。 注意事项:这个宏是一个指代宏,其中 orig-value 在这个宏中有特殊含 义,代表原来 code 对应的取值。" (declare (indent 0)) (let ((key (make-symbol "key")) (table (make-symbol "table")) (new-value (make-symbol "new-value"))) `(let* ((,key ,code) (,table ,cache) (orig-value (gethash ,key ,table)) ,new-value) (setq ,new-value (progn ,@body)) (puthash ,key ,new-value ,table)))) (defun pyim-dhashcache--insert-word-into-icode2word (word code prepend) "将词条 WORD 插入到 icode2word 词库缓存 CODE 键对应的位置. 默认 WORD 放到已有词条的最后,如果 PREPEND 为 non-nil, WORD 将放 到已有词条的最前面。" (pyim-dhashcache--put pyim-dhashcache-icode2word code (if prepend `(,word ,@(remove word orig-value)) `(,@(remove word orig-value) ,word)))) (defun pyim-dhashcache--insert-word-into-ishortcode2word (word code prepend) "将词条 WORD 插入到 ishortcode2word 词库缓存 CODE 首字母字符串对应的位置. 默认 WORD 放到已有词条的最后,如果 PREPEND 为 non-nil, WORD 将放 到已有词条的最前面。" (dolist (newcode (pyim-dhashcache--get-ishortcodes-ishortcodes code)) (pyim-dhashcache--put pyim-dhashcache-ishortcode2word newcode (if prepend `(,word ,@(remove word orig-value)) `(,@(remove word orig-value) ,word))))) (defun pyim-dhashcache--get-ishortcodes-ishortcodes (code) "获取CODE 所有的简写 ishortcodes. 比如: ni-hao -> (n-h) 注意事项:这个函数用于全拼输入法。" (when (and (> (length code) 0) (not (pyim-string-match-p "/" code)) (not (pyim-string-match-p "[^a-z-]" code))) (list (mapconcat (lambda (x) (substring x 0 1)) (remove "" (split-string code "-")) "-")))) ;; ** 从 dhashcache 删除词条相关函数 (cl-defmethod pyim-dcache-delete-word (word &context ((pyim-dcache-backend) (eql pyim-dhashcache))) "将中文词条 WORD 从个人词库中删除" (maphash (lambda (key value) (when (member word value) (let ((new-value (remove word value))) (if new-value (puthash key new-value pyim-dhashcache-icode2word) (remhash key pyim-dhashcache-icode2word))))) pyim-dhashcache-icode2word) (maphash (lambda (key value) (when (member word value) (print value) (let ((new-value (remove word value))) (if new-value (puthash key new-value pyim-dhashcache-ishortcode2word) (remhash key pyim-dhashcache-ishortcode2word))))) pyim-dhashcache-ishortcode2word) (remhash word pyim-dhashcache-iword2count) (remhash word pyim-dhashcache-iword2count-log) (remhash word pyim-dhashcache-iword2priority)) ;; ** 更新 dhashcache 相关函数 (cl-defmethod pyim-dcache-update (&context ((pyim-dcache-backend) (eql pyim-dhashcache)) &optional force) "读取并加载所有相关词库 dcache. 如果 FORCE 为真,强制加载。" (pyim-dhashcache--update-iword2priority force) (pyim-dhashcache--update-personal-words force) (let* ((dict-files (pyim-dict-get-enabled-dict-files)) (dicts-md5 (pyim-dcache-create-files-md5 dict-files))) (pyim-dhashcache--update-code2word dict-files dicts-md5 force))) (defun pyim-dhashcache--update-iword2priority (&optional force) "更新词条优先级表,如果 FORCE 为真,强制更新。" (interactive) (when (or force (not pyim-dhashcache--update-iword2priority-p)) ;; NOTE: 这个变量按理说应该在回调函数里面设置,但 async 在某些情况下会卡死, ;; 这个变量无法设置为 t, 导致后续产生大量的 emacs 进程,极其影响性能。 (setq pyim-dhashcache--update-iword2priority-p t) (async-start `(lambda () ,@(pyim-dhashcache--async-inject-variables) (require 'pyim-dhashcache) (pyim-dhashcache--init-count-and-priority-variables) (maphash (lambda (key value) (puthash key (pyim-dhashcache--calculate-priority (pyim-dhashcache--get-ishortcodes-counts-from-log value)) pyim-dhashcache-iword2priority)) pyim-dhashcache-iword2count-log) (pyim-dcache-save-variable 'pyim-dhashcache-iword2priority pyim-dhashcache-iword2priority) nil) (lambda (_) (pyim-dcache-reload-variable pyim-dhashcache-iword2priority))))) (defun pyim-dhashcache--async-inject-variables () "pyim's async-inject-variables." (list (async-inject-variables "^load-path$") (async-inject-variables "^exec-path$") (async-inject-variables "^pyim-.+?directory$"))) (defun pyim-dhashcache--calculate-priority (counts-info) "根据 COUNTS-INFO 计算优先级(优先级是多个数字组成的一个列表), 用于对词条进行排序。COUNTS-INFO 是一个 alist, 其结构类似: ((day n1 n2 n3 ...)) 其中 (n1 n2 n3 ...) 代表从当前日期逐日倒推,每日 count 所组成的列表。" (mapcar (lambda (x) (let* ((label (car x)) (plist (cdr x)) (weights (plist-get plist :weights)) (factor (plist-get plist :factor))) (round (* (apply #'+ (cl-mapcar (lambda (a b) (* (or a 0) b)) (cdr (assoc label counts-info)) weights)) factor)))) pyim-dhashcache--count-types)) (defun pyim-dhashcache--get-ishortcodes-counts-from-log (log-info &optional time) "从 LOG-INFO 中获取所有的 count 值。 比如: ((day :20220205 10 :20220204 6 => ((day 10 6 0 3 ...)) :20220202 3 ...))" (mapcar (lambda (x) (let* ((label (car x)) (plist (cdr x)) (format (plist-get plist :format)) (n (plist-get plist :max-save-length)) (delta (plist-get plist :delta)) (time (or time (current-time))) output) (dotimes (i n) (let* ((time (time-add time (days-to-time (* (- i) delta)))) (key (intern (format-time-string format time))) (plist (cdr (assoc label log-info)))) (push (or (plist-get plist key) 0) output))) `(,label ,@(reverse output)))) pyim-dhashcache--count-types)) (defun pyim-dhashcache--update-personal-words (&optional force) (pyim-dhashcache--update-icode2word force)) (defun pyim-dhashcache--update-icode2word (&optional force) "对 personal 缓存中的词条进行排序,加载排序后的结果. 在这个过程中使用了 `pyim-dhashcache-iword2count' 中记录的词频信息。 如果 FORCE 为真,强制排序。" (interactive) (when (or force (not pyim-dhashcache--update-icode2word-p)) ;; NOTE: 这个变量按理说应该在回调函数里面设置,但 async 在某些情况下会卡死, ;; 这个变量无法设置为 t, 导致后续产生大量的 emacs 进程,极其影响性能。 (setq pyim-dhashcache--update-icode2word-p t) (async-start `(lambda () ,@(pyim-dhashcache--async-inject-variables) (require 'pyim-dhashcache) (pyim-dcache-init-variable pyim-dhashcache-icode2word) (pyim-dhashcache--init-count-and-priority-variables) (maphash (lambda (key value) (puthash key (pyim-dcache-sort-words value) pyim-dhashcache-icode2word)) pyim-dhashcache-icode2word) (pyim-dcache-save-variable 'pyim-dhashcache-icode2word pyim-dhashcache-icode2word) nil) (lambda (_) (pyim-dcache-reload-variable pyim-dhashcache-icode2word) (pyim-dhashcache--update-ishortcode2word force))))) (defun pyim-dhashcache--update-ishortcode2word (&optional force) "读取 `pyim-dhashcache-icode2word' 中的词库,创建 *简拼* 缓存,然后加载这个缓存. 如果 FORCE 为真,强制加载缓存。" (interactive) (when (or force (not pyim-dhashcache--update-ishortcode2word-p)) ;; NOTE: 这个变量按理说应该在回调函数里面设置,但 async 在某些情况下会卡死, ;; 这个变量无法设置为 t, 导致后续产生大量的 emacs 进程,极其影响性能。 (setq pyim-dhashcache--update-ishortcode2word-p t) (async-start `(lambda () ,@(pyim-dhashcache--async-inject-variables) (require 'pyim-dhashcache) (pyim-dcache-init-variable pyim-dhashcache-icode2word) (pyim-dhashcache--init-count-and-priority-variables) (pyim-dcache-save-variable 'pyim-dhashcache-ishortcode2word (pyim-dhashcache--update-ishortcode2word-1 pyim-dhashcache-icode2word))) (lambda (_) (pyim-dcache-reload-variable pyim-dhashcache-ishortcode2word))))) (defun pyim-dhashcache--update-ishortcode2word-1 (icode2word) "`pyim-dhashcache--update-ishortcode2word' 内部函数." (let ((ishortcode2word (make-hash-table :test #'equal))) (maphash (lambda (key value) (dolist (newkey (pyim-dhashcache--get-ishortcodes-ishortcodes key)) (puthash newkey (delete-dups `(,@(gethash newkey ishortcode2word) ,@value)) ishortcode2word))) icode2word) (maphash (lambda (key value) (puthash key (pyim-dcache-sort-words value) ishortcode2word)) ishortcode2word) ishortcode2word)) (defun pyim-dhashcache--update-code2word (dict-files dicts-md5 &optional force) "读取并加载词库. 读取词库文件 DICT-FILES,生成对应的词库缓冲文件,然后加载词库缓存。 如果 FORCE 为真,强制加载。" (interactive) (let* ((code2word-file (pyim-dhashcache--get-ishortcodes-path 'pyim-dhashcache-code2word)) (word2code-file (pyim-dhashcache--get-ishortcodes-path 'pyim-dhashcache-word2code)) (code2word-md5-file (pyim-dhashcache--get-ishortcodes-path 'pyim-dhashcache-code2word-md5))) (when (or force (and (not (equal dicts-md5 (pyim-dcache-get-value-from-file code2word-md5-file))) (not pyim-dhashcache--update-code2word-running-p))) (setq pyim-dhashcache--update-code2word-running-p t) ;; use hashtable (async-start `(lambda () ,@(pyim-dhashcache--async-inject-variables) (require 'pyim-dhashcache) (let ((dcache (pyim-dhashcache--generate-dcache-file ',dict-files ,code2word-file))) (pyim-dhashcache--generate-word2code-dcache-file dcache ,word2code-file)) (pyim-dcache-save-value-to-file ',dicts-md5 ,code2word-md5-file)) (lambda (_) (pyim-dcache-reload-variable pyim-dhashcache-code2word) (pyim-dcache-reload-variable pyim-dhashcache-word2code) (pyim-dhashcache--update-shortcode2word force) (setq pyim-dhashcache--update-code2word-running-p nil)))))) (defun pyim-dhashcache--generate-word2code-dcache-file (dcache file) "从 DCACHE 生成一个 word -> code 的反向查询表. DCACHE 是一个 code -> words 的 hashtable. 并将生成的表保存到 FILE 中." (when (hash-table-p dcache) (let ((hashtable (make-hash-table :size 1000000 :test #'equal))) (maphash (lambda (code words) (if (pyim-string-match-p "/" code) ;; 这里主要考虑五笔仓颉等形码输入法,也就是 code-prefix 中包含 "/" ;; 的输入法, (dolist (word words) (let ((value (gethash word hashtable)) ;; NOTE: 这里使用 `cl-copy-seq', 可以让保存的文件内容类似: ;; ;; "呵" ("he" "a") ;; ;; 而不是: ;; ;; "呵" (#9="he" #2#) ;; (code (cl-copy-seq code))) (puthash word (if value `(,code ,@value) (list code)) hashtable))) ;; 使用拼音输入法时,构建词条到拼音的哈希表非常消耗内存,在这里只处理 ;; 包含多音字的词条(2-4个字),测试发现,生成的哈希表也不小,大约是 ;; code2word 的 1/4. ;; ;; 除了包含多音字的 2-4 字词条,其余词条的拼音反查功能主要使用 pymap ;; 实现,不使用这个表。 (dolist (word words) (let ((value (gethash word hashtable)) (code (cl-copy-seq code))) (when (and (> (length word) 1) (< (length word) 5) (pyim-pymap-duoyinzi-include-p word)) (puthash word (if value `(,code ,@value) (list code)) hashtable)))))) dcache) (pyim-dcache-save-value-to-file hashtable file)))) (defun pyim-dhashcache--get-ishortcodes-path (variable) "获取保存 VARIABLE 取值的文件的路径." (when (symbolp variable) (concat (file-name-as-directory pyim-dcache-directory) (symbol-name variable)))) (defun pyim-dhashcache--generate-dcache-file (dict-files dcache-file) "读取词库文件列表:DICT-FILES, 生成一个词库缓冲文件 DCACHE-FILE. pyim 使用的词库文件是简单的文本文件,编码 *强制* 为 \\='utf-8-unix, 其结构类似: ni-bu-hao 你不好 ni-hao 你好 妮好 你豪 第一个空白字符之前的内容为 code,空白字符之后为中文词条列表。词库 *不处理* 中文标点符号。" (let ((hashtable (make-hash-table :size 1000000 :test #'equal))) (dolist (file dict-files) (with-temp-buffer (let ((coding-system-for-read 'utf-8-unix)) (insert-file-contents file)) (goto-char (point-min)) (forward-line 1) (while (not (eobp)) (let* ((content (pyim-dline-parse)) (code (car content)) (words (cdr content))) (when (and code words) (puthash code (delete-dups `(,@(gethash code hashtable) ,@words)) hashtable))) (forward-line 1)))) (pyim-dcache-save-value-to-file hashtable dcache-file) hashtable)) (defun pyim-dhashcache--update-shortcode2word (&optional force) "使用 `pyim-dhashcache-code2word' 中的词条,创建简写 code 词库缓存并加载. 如果 FORCE 为真,强制运行。" (interactive) (when (or force (not pyim-dhashcache--update-shortcode2word-p)) ;; NOTE: 这个变量按理说应该在回调函数里面设置,但 async 在某些情况下会卡死, ;; 这个变量无法设置为 t, 导致后续产生大量的 emacs 进程,极其影响性能。 (setq pyim-dhashcache--update-shortcode2word-p t) (async-start `(lambda () ,@(pyim-dhashcache--async-inject-variables) (require 'pyim-dhashcache) (pyim-dcache-init-variable pyim-dhashcache-code2word) (pyim-dhashcache--init-count-and-priority-variables) (pyim-dcache-save-variable 'pyim-dhashcache-shortcode2word (pyim-dhashcache--update-shortcode2word-1 pyim-dhashcache-code2word))) (lambda (_) (pyim-dcache-reload-variable pyim-dhashcache-shortcode2word))))) (defun pyim-dhashcache--update-shortcode2word-1 (code2word) "`pyim-dhashcache--update-shortcode2word' 的内部函数" (let ((shortcode2word (make-hash-table :test #'equal))) (maphash (lambda (key value) (dolist (x (pyim-dhashcache--get-ishortcodes-shortcodes key)) (puthash x (mapcar (lambda (word) ;; 这个地方的代码用于实现五笔 code 自动提示功能, ;; 比如输入 'aa' 后得到选词框: ;; ---------------------- ;; | 1. 莁aa 2.匶wv ... | ;; ---------------------- (if (get-text-property 0 :comment word) word (propertize word :comment (substring key (length x))))) (delete-dups `(,@(gethash x shortcode2word) ,@value))) shortcode2word))) code2word) (maphash (lambda (key value) (puthash key (pyim-dcache-sort-words value) shortcode2word)) shortcode2word) shortcode2word)) (defun pyim-dhashcache--get-ishortcodes-shortcodes (code) "获取 CODE 所有的 shortcodes. 比如:wubi/aaaa -> (wubi/aaa wubi/aa) 注意事项:这个函数目前只用于五笔等型码输入法,不用于拼音输入法, 因为拼音输入法词库太大,这样处理之后,会生成一个特别大的哈希表, 占用太多内存资源,拼音输入法使用 ishortcode 机制。" (when (and (pyim-string-match-p "/" code) (not (pyim-string-match-p "-" code))) (let* ((x (split-string code "/")) (prefix (concat (nth 0 x) "/")) (code1 (nth 1 x)) (n (length code1)) results) (dotimes (i n) (when (> i 1) (push (concat prefix (substring code1 0 i)) results))) results))) ;; ** 更新 dhashcache 词频功能 (cl-defmethod pyim-dcache-update-wordcount (word &context ((pyim-dcache-backend) (eql pyim-dhashcache)) &optional wordcount-handler) (pyim-dhashcache--update-iword2count word wordcount-handler)) (defun pyim-dhashcache--update-iword2count (word &optional wordcount-handler) "保存词频到缓存." ;; 更新最近输入 10 个词条的 count 表 (setq pyim-dhashcache-iword2count-recent-10-words (pyim-dhashcache--update-iword2count-recent word 10 pyim-dhashcache-iword2count-recent-10-words)) ;; 更新最近输入 50 个词条的 count 表 (setq pyim-dhashcache-iword2count-recent-50-words (pyim-dhashcache--update-iword2count-recent word 50 pyim-dhashcache-iword2count-recent-50-words)) ;; 更新总 count 表 (pyim-dhashcache--put pyim-dhashcache-iword2count word (cond ((functionp wordcount-handler) (funcall wordcount-handler (or orig-value 0))) ((numberp wordcount-handler) wordcount-handler) (t (or orig-value 0)))) ;; 更新 count 日志表。 (pyim-dhashcache--put pyim-dhashcache-iword2count-log word (let (out) (dolist (x pyim-dhashcache--count-types) (let* ((label (car x)) (key (intern (format-time-string (plist-get (cdr x) :format)))) (n (plist-get (cdr x) :max-save-length)) (plist (cdr (assoc label orig-value))) (value (plist-get plist key)) (output (if value (plist-put plist key (+ 1 value)) (append (list key 1) plist))) (length (length output)) (output (cl-subseq output 0 (min length (* 2 n))))) (push `(,label ,@output) out))) out)) ;; 更新优先级表 (pyim-dhashcache--put pyim-dhashcache-iword2priority word ;; Fix warn (ignore orig-value) (pyim-dhashcache--calculate-priority (pyim-dhashcache--get-ishortcodes-counts-from-log (gethash word pyim-dhashcache-iword2count-log))))) (defun pyim-dhashcache--update-iword2count-recent (word n hash-table) (let (words-need-remove) (pyim-dhashcache--put hash-table :all-words (setq orig-value (remove word orig-value)) (push word orig-value) (if (<= (length orig-value) n) orig-value (setq words-need-remove (nthcdr n orig-value)) (cl-subseq orig-value 0 n))) (dolist (w words-need-remove) (remhash w hash-table)) (pyim-dhashcache--put hash-table word (+ (or orig-value 0) 1)) hash-table)) ;; ** 根据 dhashcache 信息对词条进行排序 (cl-defmethod pyim-dcache-sort-words (words-list &context ((pyim-dcache-backend) (eql pyim-dhashcache))) "对 WORDS-LIST 排序" (let ((iword2count pyim-dhashcache-iword2count) (iword2priority pyim-dhashcache-iword2priority)) (sort words-list (lambda (a b) (let ((p1 (gethash a iword2priority)) (p2 (gethash b iword2priority))) (cond ((and (listp p1) (listp p2) (not (equal p1 p2))) (pyim-numbers> p1 p2)) (t (let ((n1 (or (gethash a iword2count) 0)) (n2 (or (gethash b iword2count) 0))) (> n1 n2))))))))) ;; ** 升级 dhashcache 相关函数 (cl-defmethod pyim-dcache-upgrade (&context ((pyim-dcache-backend) (eql pyim-dhashcache))) "升级词库缓存. 当前已有的功能: 1. 基于 :code-prefix-history 信息,升级为新的 code-prefix。" (pyim-dhashcache--upgrade-icode2word (yes-or-no-p "Delete old key after upgrade? "))) (defun pyim-dhashcache--upgrade-icode2word (&optional delete-old-key) "升级 icode2word 缓存。" (dolist (ruler (pyim-dhashcache--upgrade-icode2word-rulers)) (let ((old-prefix-list (car ruler)) (new-prefix (cdr ruler))) (dolist (old-prefix old-prefix-list) (maphash (lambda (key _value) (if (string-prefix-p old-prefix key) (let* ((key-words (gethash key pyim-dhashcache-icode2word)) (new-key (concat new-prefix (string-remove-prefix old-prefix key))) (new-key-words (gethash new-key pyim-dhashcache-icode2word)) (merged-value (delete-dups `(,@new-key-words ,@key-words)))) (puthash new-key merged-value pyim-dhashcache-icode2word) (message "PYIM: %S %S -> %S %S in `pyim-dhashcache-icode2word'." key key-words new-key merged-value) (when delete-old-key (remhash key pyim-dhashcache-icode2word) (message "PYIM: %S has been deleted in `pyim-dhashcache-icode2word'." key))) (message "PYIM: No need to upgrade in `pyim-dhashcache-icode2word'."))) pyim-dhashcache-icode2word))))) (defun pyim-dhashcache--upgrade-icode2word-rulers () "返回 icode2word 升级规则。 类似: (((\".\") . \"wubi/\") ((\"@\") . \"cangjie/\"))." (delete-dups (remove nil (mapcar (lambda (scheme) (let ((code-prefix (pyim-scheme-code-prefix scheme)) (code-prefix-history (pyim-scheme-code-prefix-history scheme))) (when code-prefix-history (cons code-prefix-history code-prefix)))) (pyim-scheme-get-all-schemes))))) ;; ** 保存 dhashcache 相关函数 (cl-defmethod pyim-dcache-save-caches (&context ((pyim-dcache-backend) (eql pyim-dhashcache))) (pyim-dhashcache--save-personal-dcache-to-file)) (defun pyim-dhashcache--save-personal-dcache-to-file () ;; 用户选择过的词 (pyim-dcache-save-variable 'pyim-dhashcache-icode2word pyim-dhashcache-icode2word 0.8) ;; 词条总 count (pyim-dcache-save-variable 'pyim-dhashcache-iword2count pyim-dhashcache-iword2count 0.8) ;; 词条 count 日志 (pyim-dcache-save-variable 'pyim-dhashcache-iword2count-log pyim-dhashcache-iword2count-log 0.8) ;; 词条优先级 (pyim-dcache-save-variable 'pyim-dhashcache-iword2priority pyim-dhashcache-iword2priority 0.8)) ;; ** 导出相关函数 (cl-defmethod pyim-dcache-export-personal-words (file &context ((pyim-dcache-backend) (eql pyim-dhashcache)) &optional confirm) "导出个人词库到 FILE." (pyim-dhashcache--export pyim-dhashcache-icode2word file confirm)) (defun pyim-dhashcache--export (dcache file &optional confirm) "将一个 pyim DCACHE 导出为文件 FILE. 如果 CONFIRM 为 non-nil,文件存在时将会提示用户是否覆盖, 默认为覆盖模式" (with-temp-buffer (let (export-lines) (maphash (lambda (key value) (let ((value (cl-remove-if (lambda (x) ;; 如果某个词条的 text 属性 :noexport 设置为 t, 在导出的 ;; 时候自动忽略这个词条。 (and (stringp x) (get-text-property 0 :noexport x))) (if (listp value) value (list value))))) (when value (push (format "%s %s\n" key (mapconcat #'identity value " ")) export-lines)))) dcache) (setq export-lines (sort export-lines #'string<)) (goto-char (point-min)) (insert ";;; -*- coding: utf-8-unix -*-\n") (dolist (line export-lines) (insert line)) (pyim-dcache-write-file file confirm)))) (cl-defmethod pyim-dcache-export-words-and-counts (file &context ((pyim-dcache-backend) (eql pyim-dhashcache)) &optional confirm ignore-counts) (with-temp-buffer (let (export-lines) (maphash (lambda (key value) (push (if ignore-counts (format "%s\n" key) (format "%s %s\n" key value)) export-lines)) pyim-dhashcache-iword2count) ;; 在默认情况下,用户选择过的词生成的缓存中存在的词条, ;; `pyim-dhashcache-iword2count' 中也一定存在,但如果用户 ;; 使用了特殊的方式给用户选择过的词生成的缓存中添加了 ;; 词条,那么就需要将这些词条也导出,且设置词频为 0 (maphash (lambda (_ words) (dolist (word words) (unless (gethash word pyim-dhashcache-iword2count) (push (if ignore-counts (format "%s\n" word) (format "%s %s\n" word 0)) export-lines)))) pyim-dhashcache-icode2word) (setq export-lines (sort export-lines #'pyim-dhashcache--pinyin-string<)) (goto-char (point-min)) (insert ";;; -*- coding: utf-8-unix -*-\n") (dolist (line export-lines) (insert line)) (pyim-dcache-write-file file confirm)))) (defun pyim-dhashcache--pinyin-string< (a b) "比较 A 和 B 两个字符串的拼音的大小。" (let ((pinyin1 (pyim-cstring-to-pinyin-simple a)) (pinyin2 (pyim-cstring-to-pinyin-simple b))) (string< pinyin1 pinyin2))) ;; * Footer (provide 'pyim-dhashcache) ;;; pyim-dhashcache.el ends here pyim-5.3.3/pyim-dcache.el0000644000175000017500000002473714412763713015064 0ustar dogslegdogsleg;;; pyim-dcache.el --- dcache tools for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-common) (require 'pyim-pymap) (require 'pyim-scheme) (require 'url-util) (defgroup pyim-dcache nil "Dcache for pyim." :group 'pyim) (defcustom pyim-dcache-directory (locate-user-emacs-file "pyim/dcache/") "一个目录,用于保存 pyim 词库对应的 cache 文件." :type 'directory :group 'pyim) (defcustom pyim-dcache-backend 'pyim-dhashcache "词库后端引擎,负责缓冲词库并提供搜索词条的算法。 目前有两个选项: 1. `pyim-dhashcache' 2. `pyim-dregcache' `pyim-dhashcache' 是 pyim 默认使用的后端,使用 hashtable 实现,搜 索词条速度很快,但消耗内存多。 `pyim-dregcache' 消耗内存少,搜索速度和词库大小成反比,当词库小于 100M 时,速度还可以,可以尝试,需要注意的是,这个后端只支持全拼和 双拼输入法,不支持型码输入法,如果使用这个后端,用户需要自己在 Emacs 配置中添加 (require \\='pyim-dregcache)." :type '(radio (const pyim-dhashcache) (const pyim-dregcache))) (defvar pyim-dcache-auto-update t "是否自动创建和更新词库对应的 dcache 文件. 这个变量默认设置为 t, 用户添加新的词库文件时,pyim 会自动生成相关 的 dcache 文件。 一般不建议将这个变量设置为 nil,除非有以下情况: 1. 用户的词库已经非常稳定,并且想通过禁用这个功能来降低 pyim 对资源的消耗。 2. 自动更新功能无法正常工作,用户通过手工从其他机器上拷贝 dcache 文件的方法让 pyim 正常工作。") ;; ** Dcache 变量初始化相关函数 (defmacro pyim-dcache-init-variable (variable &optional fallback-value) "初始化 VARIABLE. 如果 VARIABLE 的值为 nil, 则使用 `pyim-dcache-directory' 中对应文 件的内容来设置 VARIABLE 变量, 如果此时 VARIABLE 取值还是 nil, 那 么就将 VARIABLE 的值设置为 FALLBACK-VALUE." `(when (and (symbolp ',variable) (not ,variable)) (setq ,variable (or (pyim-dcache-get-value ',variable) ,fallback-value (make-hash-table :test #'equal))))) (defun pyim-dcache-get-value (variable) "从 `pyim-dcache-directory' 中读取与 VARIABLE 对应的文件中保存的值." (let ((file (expand-file-name (url-hexify-string (symbol-name variable)) pyim-dcache-directory))) (pyim-dcache-get-value-from-file file))) (defun pyim-dcache-get-value-from-file (file) "读取保存到 FILE 里面的 value." (when (and (> (length file) 0) (file-exists-p file)) (with-temp-buffer (insert-file-contents file) (ignore-errors (read (current-buffer)))))) ;; ** Dcache 保存变量相关函数 (defun pyim-dcache-save-variable (variable value &optional auto-backup-threshold) "将 VARIABLE 变量的取值保存到 `pyim-dcache-directory' 中对应文件中. 如果 VALUE 的长度小于先前保存值的长度的 AUTO-BACKUP-THRESHOLD 倍, 那么先前保存的值将自动备份到相应的备份文件。" (let ((file (expand-file-name (url-hexify-string (symbol-name variable)) pyim-dcache-directory))) (pyim-dcache-save-value-to-file value file auto-backup-threshold))) (defun pyim-dcache-save-value-to-file (value file &optional auto-backup-threshold) "将 VALUE 保存到 FILE 文件中. 如果 VALUE 的长度小于 FILE 中上次保存值的长度的 AUTO-BACKUP-THRESHOLD 倍, 那么原值将自动备份到 FILE 对应的备份文 件。" (make-directory (file-name-directory file) t) (let* ((backup-file (concat file "-backup-" (format-time-string "%Y%m%d%H%M%S"))) (orig-value (pyim-dcache-get-value-from-file file)) (orig-length (pyim-dcache--value-length orig-value)) (length (pyim-dcache--value-length value))) (when (and (numberp auto-backup-threshold) (< length (* auto-backup-threshold orig-length))) (pyim-dcache-save-value-to-file orig-value backup-file) (message "PYIM: 生成备份文件 %S, 请检查原文件 %S 是否损坏!!!" backup-file file)) (when value (with-temp-buffer (insert ";; -*- lisp-data -*-\n") (insert ";; Auto generated by `pyim-dhashcache--save-variable-to-file', don't edit it by hand!\n") (insert (format ";; Build time: %s\n\n" (current-time-string))) (insert (let ((print-level nil) (print-circle t) (print-length nil)) (prin1-to-string value))) (insert "\n\n") (insert ";; Local\sVariables:\n") ;Use \s to avoid a false positive! (insert ";; coding: utf-8-unix\n") (insert ";; End:") (pyim-dcache-write-file file))))) (defun pyim-dcache--value-length (value) "获取 VALUE 的某个可以作为长度的值." (or (ignore-errors (if (hash-table-p value) (hash-table-count value) (length value))) 0)) (defun pyim-dcache-write-file (filename &optional confirm) "A helper function to write dcache files." (let ((coding-system-for-write 'utf-8-unix) (create-lockfiles nil)) (and confirm (file-exists-p filename) ;; NS does its own confirm dialog. (not (and (eq (framep-on-display) 'ns) (listp last-nonmenu-event) use-dialog-box)) (or (y-or-n-p (format-message "File `%s' exists; overwrite? " filename)) (user-error "Canceled"))) (write-region (point-min) (point-max) filename nil :silent) (message "Saving file %s..." filename))) (defun pyim-dcache-create-files-md5 (files) "为 FILES 生成 md5 字符串。" ;; 当需要强制更新 dict 缓存时,更改这个字符串。 (let ((version "v1")) (md5 (prin1-to-string (mapcar (lambda (file) (list version file (nth 5 (file-attributes file 'string)))) files))))) ;; ** Dcache 重新加载变量相关函数 (defmacro pyim-dcache-reload-variable (variable) "从 `pyim-dcache-directory' 重新读取并设置 VARIABLE 的值." `(when (symbolp ',variable) (setq ,variable (or (pyim-dcache-get-value ',variable) (make-hash-table :test #'equal))))) ;; ** Dcache 获取当前可用后端接口 (cl-defgeneric pyim-dcache-backend () "返回当前可用的 dcache backend." (if (featurep pyim-dcache-backend) pyim-dcache-backend 'pyim-dhashcache)) ;; ** Dcache 初始化功能接口 (cl-defgeneric pyim-dcache-init-variables () "初始化 dcache 缓存相关变量.") ;; ** Dcache 检索词条功能接口 (cl-defgeneric pyim-dcache-get (_key &optional _from) "从 FROM 中搜索 KEY, 得到对应的取值. FORM 是一个包含下面几个符号的 list, 每个符号代表一种类型的 dcache. * 编码 -> 词条 1. code2word 用编码搜索词条 2. shortcode2word 用简码搜索词条 3. icode2word 用编码搜索个人词条 4. ishortcode2word 用简码搜索个人词条 * 词条 -> 编码 1. word2code 用词条搜索编码 * 词条 -> 词频 1. iword2count 搜索个人词条的词频 2. iword2count-recent-10-words 搜索最近输入10个词条的词频 3. iword2count-recent-50-words 搜索最近输入50个词条的词频 如果 FROM 是 nil, 那么 fallback 到 \\='(icode2word code2word)." nil) ;; ** Dcache 加词功能接口 (cl-defgeneric pyim-dcache-insert-word (word code prepend) "将词条 WORD 插入到 dcache 中。 如果 PREPEND 为 non-nil, 词条将放到 CODE 已有对应词条的最前面。") ;; ** Dcache 删词功能 (cl-defgeneric pyim-dcache-delete-word (word) "将中文词条 WORD 从个人词库中删除") ;; ** Dcache 更新功能接口 (cl-defgeneric pyim-dcache-update (&optional force) "读取并加载所有相关词库 dcache, 如果 FORCE 为真,强制加载。") ;; ** Dcache 更新词频功能接口 (cl-defgeneric pyim-dcache-update-wordcount (word &optional wordcount-handler) "更新 WORD 词频. 1. 如果 WORDCOUNT-HANDLER 是一个函数:那么其返回值将作为词频保存, 参数为原有词频。 2. 如果 WORDCOUNT-HANDLER 是一个数值:那么这个数值直接作为词频保存。 3. 如果 WORDCOUNT-HANDLER 为其他值:词频不变.") ;; ** Dcache 升级功能接口 (cl-defgeneric pyim-dcache-upgrade () "升级词库缓存.") ;; ** Dcache 排序功能接口 (cl-defgeneric pyim-dcache-sort-words (words) "对 WORDS 进行排序。" words) ;; ** Dcache 保存功能接口 (cl-defgeneric pyim-dcache-save-caches () "保存 dcache. 将用户选择过的词生成的缓存和词频缓存的取值 保存到它们对应的文件中.") ;; ** Dcache 导出功能接口 (cl-defgeneric pyim-dcache-export-words-and-counts (file &optional confirm ignore-counts) "将个人词条以及词条对应的词频信息导出到文件 FILE. 如果 FILE 为 nil, 提示用户指定导出文件位置, 如果 CONFIRM 为 non-nil,文件存在时将会提示用户是否覆盖,默认为覆盖模式") (cl-defgeneric pyim-dcache-export-personal-words (file &optional confirm) "将用户的个人词条导出为 pyim 词库文件. 如果 FILE 为 nil, 提示用户指定导出文件位置, 如果 CONFIRM 为 non-nil, 文件存在时将会提示用户是否覆盖,默认为覆盖模式。") ;; * Footer (provide 'pyim-dcache) ;;; pyim-dcache.el ends here pyim-5.3.3/pyim-cregexp-utils.el0000644000175000017500000001140014306057123016420 0ustar dogslegdogsleg;;; pyim-cregexp-utils.el --- Chinese regexp tools for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'pyim-cregexp) (require 'pyim-dhashcache) (defgroup pyim-cregexp nil "Chinese regexp tools for pyim." :group 'pyim) (defcustom pyim-cregexp-convert-at-point-function #'pyim-cregexp-convert-at-point-function "`pyim-cregexp-convert-at-point' 使用的函数。 此函数有一个参数 cregexp, 表示生成的 cregexp. 其返回值会插入当前 buffer." :type 'function) ;;;###autoload (defun pyim-cregexp-convert-at-point (&optional insert-only) "将光标前的字符串按拼音的规则转换为一个搜索中文的 regexp. 用于实现拼音搜索中文的功能。 在 minibuffer 中,这个命令默认会自动运行 `exit-minibuffer'. 这个可以使用 INSERT-ONLY 参数控制。" (interactive "P") (pyim-pymap-cache-create) (let* ((string (if mark-active (buffer-substring-no-properties (region-beginning) (region-end)) (buffer-substring (point) (save-excursion (skip-syntax-backward "w") (point))))) (length (length string)) (cregexp (pyim-cregexp-build string))) (delete-char (- 0 length)) (insert (funcall pyim-cregexp-convert-at-point-function cregexp)) (when (and (not insert-only) (window-minibuffer-p)) (exit-minibuffer)))) (defun pyim-cregexp-convert-at-point-function (cregexp) "这个函数是变量 `pyim-cregexp-convert-at-point-function' 的默认取值。" (cond ;; Deal with `org-search-view' ((and (window-minibuffer-p) (string-match-p (regexp-quote "[+-]Word/{Regexp}") (buffer-substring (point-min) (point-max)))) (format "{%s}" cregexp)) (t cregexp))) ;; 让 isearch 支持用 code 搜索中文功能 (declare-function isearch-search-fun "isearch") (defvar isearch-forward) ;;;###autoload (define-minor-mode pyim-isearch-mode "这个 mode 为 isearch 添加拼音搜索功能." :global t :require 'pyim :lighter " pyim-isearch" (if pyim-isearch-mode (progn (advice-add 'isearch-search-fun :override #'pyim-isearch--search-fun) (message "PYIM: `pyim-isearch-mode' 已经激活,激活后,一些 isearch 扩展包有可能失效。")) (advice-remove 'isearch-search-fun #'pyim-isearch--search-fun))) (defun pyim-isearch--search-fun () "这个函数为 isearch 相关命令添加中文拼音搜索功能, 做为 `isearch-search-fun' 函数的 advice 使用。" (funcall (lambda () `(lambda (string &optional bound noerror count) (funcall (if ,isearch-forward 're-search-forward 're-search-backward) ;; FIXME: 搜索字符串中的 '\' 不太好处理,如果遇到, 目前的做法是 ;; 不做任何处理,这个是需要改进的地方。 (if (string-match-p "\\\\" string) (regexp-quote string) (pyim-cregexp-build string)) bound noerror count))))) ;; 让 ivy 支持 code 搜索。 (declare-function ivy--regex-plus "ivy") (defun pyim-cregexp-ivy (str) "Let ivy support search Chinese with pinyin feature." (let ((x (ivy--regex-plus str)) (case-fold-search nil)) (if (listp x) (mapcar (lambda (y) (if (cdr y) (list (if (equal (car y) "") "" (pyim-cregexp-build (car y))) (cdr y)) (list (pyim-cregexp-build (car y))))) x) (pyim-cregexp-build x)))) ;; * Footer (provide 'pyim-cregexp-utils) ;;; pyim-cregexp-utils.el ends here pyim-5.3.3/pyim-page.el0000644000175000017500000006135614412763713014567 0ustar dogslegdogsleg;;; pyim-page.el --- page lib for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'posframe nil t) (require 'pyim-common) (require 'pyim-process) (defgroup pyim-page nil "Page tools for pyim." :group 'pyim) (defcustom pyim-page-length 5 "每页显示的词条数目. 细节信息请参考 `pyim-page--refresh' 的 docstring." :type 'number) (define-widget 'pyim-page-tooltip-1 'lazy nil :type '(choice (const posframe) (const popup) (const popon) (const minibuffer))) (define-widget 'pyim-page-tooltip 'lazy "如何绘制 pyim 选词框,详见变量 `pyim-page-tooltip'。" :type '(choice (pyim-page-tooltip-1 :tag "单一选词框") (repeat :tag "依次选择可用选词框" pyim-page-tooltip-1))) (defcustom pyim-page-tooltip '(posframe popup minibuffer) "如何绘制 pyim 选词框. 1. 当这个变量取值为 posframe 时,使用 posframe 包来绘制选词框, 使用 Emacs 26 图形版的用户推荐使用这个选项。 2. 当这个变量取值为 popup 时,使用 popup-el 包来绘制选词框, 这个选项可以在 Emacs 图形版和终端版使用,速度没有 posframe 快, 偶尔会遇到选词框错位的问题。 3. 当这个变量取值为 popon 时,使用 popon 包来绘制选词框,这个选项 效果类似 popup。 4. 当这个变量取值为 minibuffer 时,minibuffer 将做为选词框, 这个选项也作为其他选项不可用时的 fallback. 5. 当这个变量的取值是为一个 list 时,pyim 将按照优先顺序动态 选择一个当前环境可用的 tooltip." :type 'pyim-page-tooltip) (define-widget 'pyim-page-style 'lazy "选词框的格式" :type '(choice (const :tag "单行选词框" two-lines) (const :tag "双行选词框" one-line) (const :tag "垂直选词框" vertical) (const :tag "单行选词框 (minibuffer)" minibuffer))) (defcustom pyim-page-style 'two-lines "这个变量用来控制选词框的格式. pyim 内建的有四种选词框格式: 1. one-line 单行选词框 2. two-lines 双行选词框 3. vertical 垂直选词框 4. minibuffer 单行选词框 (minibuffer 中专用)" :type 'pyim-page-style) (defcustom pyim-page-tooltip-style-alist '((minibuffer . minibuffer)) "pyim page tooltip 专用 page style 绑定设置表。 这个表是一个 alist, 每个元素的 car 代表 tooltip, cdr 代表对应的 page style." :type '(alist :key-type pyim-page-tooltip-1 :value-type pyim-page-style)) (defcustom pyim-page-posframe-border-width 0 "posframe的内间距。 只有当用户使用 posframe 来显示候选词时才有效。" :type 'integer) (defcustom pyim-page-posframe-min-width (* pyim-page-length 7) "使用 posframe 做为选词框时,设置选词框的最小宽度." :type 'integer) (defcustom pyim-page-minibuffer-separator nil "在 minibuffer 中使用 pyim 时,preview 和 page 之间的分割字符串。" :type '(choice (const :tag "No user defined separator" nil) string)) (defface pyim-page '((t (:inherit default :background "#333333" :foreground "#dcdccc"))) "Face used for the pyim page.") (defface pyim-page-border '((t (:inherit pyim-page :background "gray"))) "Face used for the pyim page border. Only useful when use posframe.") (defface pyim-page-selection '((t (:background "gray44"))) "选词框中已选词条的 face.") (defvar pyim-page-tooltip-infos '((posframe :package posframe :test posframe-workable-p) (popup :package popup) (popon :package popon) (minibuffer :package minibuffer)) "pyim-page tooltip 相关信息。 用于函数 `pyim-page--tooltip-valid-p'.") (defun pyim-page--refresh (&optional hightlight-current) "刷新 page 页面的函数. 这个函数主要用来处理选词框选词后,刷新显示问题, \"nihao\" 对应的 *待选词列表* 类似: (\"你好\" \"倪皓\" \"泥\" \"你\" ... \"慝\") *待选词列表* 一般都很长,不可能在一页中完全显示,所以 pyim 使用了 page 的概念,比如,上面的 “nihao” 的 *待选词列表* 就可以逻辑的 分成5页: 第1页 你好 倪皓 泥 你 呢 拟 逆 腻 妮 第2页 怩 溺 尼 禰 齯 麑 鲵 蜺 衵 第3页 薿 旎 睨 铌 昵 匿 倪 霓 暱 第4页 柅 猊 郳 輗 坭 惄 堄 儗 伲 第5页 祢 慝 `pyim-process-word-position' 的返回值以及 `pyim-page-length' 的设 定值(默认设置为9),共同决定了 pyim 需要显示哪一页,比如: 第1页 你好 倪皓 泥 你 呢 拟 逆 腻 妮 第2页 怩 溺 尼 禰 齯 麑 鲵 蜺 衵 第3页 薿[B] 旎 睨[A] 铌 昵 匿 倪 霓 暱[E] 第4页 柅 猊 郳 輗 坭 惄 堄 儗 伲 第5页 祢 慝 假设当前选择的词条为 \"睨\", 那么 `pyim-process-word-position' 的返回值为 A 所在的位置。那么: 1. 函数 `pyim-page--current-page' 返回值为3, 说明当前 page 为第3页。 2. 函数 `pyim-page--total-page' 返回值为5,说明 page 共有5页。 3. 函数 `pyim-page--start' 返回 B 所在的位置。 4. 函数 `pyim-page--end' 返回 E 所在的位置。 5. 函数 `pyim-page--refresh' 会从待选词条列表中提取一个 sublist: (\"薿\" \"旎\" \"睨\" \"铌\" \"昵\" \"匿\" \"倪\" \"霓\" \"暱\") 这个 sublist 的起点为 `pyim-page--start' 的返回值,终点为 `pyim-page--end' 的返回值。并保存到一个 plist 的 :candidates 对应 的位置,这个 plist 最终会做为参数传递给 `pyim-page-style' 相关的 函数,用于生成用于在选词框中显示的字符串。" (let* ((candidates-showed (pyim-page--get-showed-candidates)) (position (pyim-page--word-position-in-current-page)) (tooltip (pyim-page--get-valid-tooltip)) (style (pyim-page--get-page-style tooltip)) (page-info (list :scheme (pyim-scheme-current) :current-page (pyim-page--current-page) :total-page (pyim-page--total-page) :candidates candidates-showed :position position :hightlight-current hightlight-current :assistant-enable (pyim-scheme-assistant-enable-p)))) ;; Show page. (when (and (null unread-command-events) (null unread-post-input-method-events)) (pyim-page-show (pyim-page-info-format style page-info) (pyim-process-ui-position) tooltip)))) (add-hook 'pyim-process-ui-refresh-hook #'pyim-page--refresh) (defun pyim-page--get-showed-candidates () "从 CANDIDATES 中获取当前 page 显示需要显示的部分内容。" (mapcar (lambda (x) (let ((comment (get-text-property 0 :comment x))) (if comment (concat x comment) x))) (cl-subseq (pyim-process-get-candidates) (pyim-page--start) (pyim-page--end)))) (defun pyim-page--start (&optional position) "计算当前所在页的第一个词条的位置. 细节信息请参考 `pyim-page--refresh' 的 docstring." (* (/ (pyim-process-word-position position) pyim-page-length) pyim-page-length)) (defun pyim-page--end () "计算当前所在页的最后一个词条的位置, 细节信息请参考 `pyim-page--refresh' 的 docstring." (let* ((whole (pyim-process-candidates-length)) (len pyim-page-length) (pos (pyim-process-word-position)) (last (* (/ (+ pos len) len) len))) (if (< last whole) last whole))) (defun pyim-page--word-position-in-current-page () "获取当前选择的词条在在当前 page 中的位置。" (- (pyim-process-word-position) (pyim-page--start))) (defun pyim-page--get-valid-tooltip () "根据当前环境,获取一个可用的 tooltip." (cond ;; NOTE: 以前在 minibuffer 中试用过 posframe, linux 环境下运行效果还不错,但 ;; 在 windows 环境下,似乎有很严重的性能问题,原因未知。 ((eq (selected-window) (minibuffer-window)) 'minibuffer) ;; 在 exwm-xim 环境下输入中文时,只能使用 minibuffer, 因为应用窗口遮挡的缘故, ;; 其它方式不可用。 ((pyim-exwm-xim-environment-p) 'minibuffer) (t (or (cl-find-if #'pyim-page--tooltip-valid-p (if (listp pyim-page-tooltip) pyim-page-tooltip (list pyim-page-tooltip))) 'minibuffer)))) (defun pyim-page--tooltip-valid-p (tooltip) "测试 TOOLTIP 当前是否可用。" (let* ((info (alist-get tooltip pyim-page-tooltip-infos)) (package (plist-get info :package)) (test-func (plist-get info :test))) (cond ((not (featurep package)) nil) ((not (functionp test-func)) t) ((and (functionp test-func) (funcall test-func)) t) (t nil)))) (defun pyim-page--get-page-style (tooltip) "依照 TOOLTIP 和 `pyim-page-style', 得到一个 page style." (or (cdr (assoc tooltip pyim-page-tooltip-style-alist)) pyim-page-style)) (defun pyim-page--current-page () "计算当前选择的词条在第几页面. 细节信息请参考 `pyim-page--refresh' 的 docstring." (1+ (/ (pyim-process-word-position) pyim-page-length))) (defun pyim-page--total-page () "计算 page 总共有多少页. 细节信息请参考 `pyim-page--refresh' 的 docstring." (let* ((length (pyim-process-candidates-length)) (n (/ length pyim-page-length))) (if (> length (* n pyim-page-length)) (1+ n) n))) (cl-defgeneric pyim-page-show (string position tooltip) "在 POSITION 位置,使用 TOOLTIP 显示字符串 STRING. 注意事项: pyim-page 将背景颜色设置功能放置在 `pyim-page-show' , 因为在 `pyim-page-info-format' 中实现此功能,需要计算字符串宽度和 补充空格,添加 text propertize, 过程相当啰嗦,而背景颜色设置不是 pyim-page 的核心的功能,为此增加代码的复杂度和测试的难度感觉得不 偿失。 所以我们的选择是:尽量选择支持背景颜色设置的 tooltip, 如果不支持, 就放弃这个功能。") (defvar pyim-page--posframe-buffer " *pyim-page--posframe-buffer*" "这个变量用来保存做为 page tooltip 的 posframe 的 buffer.") (cl-defmethod pyim-page-show (string position (_tooltip (eql posframe))) "在 POSITION 位置,使用 posframe STRING." (posframe-show pyim-page--posframe-buffer :string string :position position :min-width pyim-page-posframe-min-width :background-color (face-attribute 'pyim-page :background) :foreground-color (face-attribute 'pyim-page :foreground) :border-width pyim-page-posframe-border-width :border-color (face-attribute 'pyim-page-border :background))) (defvar pyim-page--minibuffer-string nil "函数 `pyim-page-show-with-minibuffer' 上一次处理的消息字符串。") (cl-defmethod pyim-page-show (string _position (_tooltip (eql minibuffer))) "使用 minibuffer 来显示 STRING。" (let ((max-mini-window-height (+ pyim-page-length 2)) (message-log-max nil)) (if (not (eq (selected-window) (minibuffer-window))) (message string) (message nil) ;; 在类似 vertico-posframe 这样的环境中,posframe window-point 同步问题不 ;; 太好处理,这里使用一个简单粗暴的方式:在输入过程中,隐藏真实的 cursor ;; 并显示一个伪 cursor, 输入完成之后再恢复。 (setq-local cursor-type nil) ;; 异步获取词条的时候,上一次的 page 字符串可能还在 Minibuffer 中,所以首 ;; 先要将其去除,否则会出现两个 page. (delete-char (length pyim-page--minibuffer-string)) (save-excursion (insert (setq pyim-page--minibuffer-string (concat ;; 显示一个伪 cursor. (propertize " " 'face 'cursor) (or pyim-page-minibuffer-separator (let* ((width (string-width (buffer-string))) (n (- (* 20 (+ 1 (/ width 20))) width))) (make-string n ?\ ))) string))))))) (declare-function popup-tip "popup") (declare-function popup-delete "popup") (defvar popup-version) (defvar pyim-page--popup nil "这个变量用来保存做为 page tooltip 的 popup.") (cl-defmethod pyim-page-show (string position (_tooltip (eql popup))) "Show STRING at POSITION with the help of popup-el." (when pyim-page--popup ;; 延迟获取词条的时候,如果不把已经存在的 popup 删除,就会出现两个 page. (popup-delete pyim-page--popup)) (setq pyim-page--popup (apply #'popup-tip string :point position :around t :nowait t :nostrip t ;; popup v0.5.9 以后才支持 face 参数 (unless (version<= popup-version "0.5.8") (list :face 'pyim-page))))) (declare-function popon-create "popon") (declare-function popon-kill "popon") (declare-function popon-x-y-at-pos "popon") (defvar pyim-page--popon nil "这个变量用来保存做为 page tooltip 的 popon.") (cl-defmethod pyim-page-show (string position (_tooltip (eql popon))) "Show STRING at POSITION with the help of popon." (when pyim-page--popon ;; 延迟获取词条的时候,如果不把已经存在的 popon 删除,就会出现两个 page. (popon-kill pyim-page--popon)) (let* ((x-y (popon-x-y-at-pos position)) (x (car x-y)) (y (cdr x-y))) (setq pyim-page--popon (popon-create (pyim-page--add-default-page-face (pyim-page--align-lines string)) (cons x (+ y 1)))))) (defun pyim-page--add-default-page-face (string) "为 STRING 添加默认 page face." (with-temp-buffer (insert string) (add-face-text-property (point-min) (point-max) 'pyim-page t) (buffer-string))) (defun pyim-page--align-lines (string) "用空格将 STRING 的每一行都对齐。" (let* ((lines (split-string string "\n")) (widths (mapcar #'string-width lines)) (max-width (apply #'max widths)) (new-lines (mapcar (lambda (line) (concat line (make-string (- max-width (string-width line)) ?\ ))) lines))) (string-join new-lines "\n"))) (cl-defgeneric pyim-page-info-format (style page-info) "将 PAGE-INFO 按照 STYLE 格式化为选词框中显示的字符串。") (cl-defmethod pyim-page-info-format (_style page-info) "将 PAGE-INFO 格式化为选词框中显示的字符串. 样式类似: +----------------------------+ | ni hao [1/9] | | 1.你好 2.你号 ... | +----------------------------+" (format "=> %s%s [%s/%s]: \n%s" (pyim-page-preview-create (plist-get page-info :scheme)) (if (plist-get page-info :assistant-enable) " (辅)" "") (plist-get page-info :current-page) (plist-get page-info :total-page) (pyim-page-menu-create (plist-get page-info :candidates) (plist-get page-info :position) nil (plist-get page-info :hightlight-current)))) (cl-defmethod pyim-page-info-format ((_style (eql one-line)) page-info) "将 PAGE-INFO 格式化为选词框中显示的字符串. 样式类似: +-----------------------------------+ | [ni hao]: 1.你好 2.你号 ... (1/9) | +-----------------------------------+" (format "[%s%s]: %s(%s/%s)" (pyim-page-preview-create (plist-get page-info :scheme) " ") (if (plist-get page-info :assistant-enable) " (辅)" "") (pyim-page-menu-create (plist-get page-info :candidates) (plist-get page-info :position) nil (plist-get page-info :hightlight-current)) (plist-get page-info :current-page) (plist-get page-info :total-page))) (cl-defmethod pyim-page-info-format ((_style (eql vertical)) page-info) "将 PAGE-INFO 格式化为选词框中显示的字符串. 样式类似: +--------------+ | ni hao [1/9] | | 1.你好 | | 2.你号 ... | +--------------+" (format "=> %s%s [%s/%s]: \n%s" (pyim-page-preview-create (plist-get page-info :scheme)) (if (plist-get page-info :assistant-enable) " (辅)" "") (plist-get page-info :current-page) (plist-get page-info :total-page) (pyim-page-menu-create (plist-get page-info :candidates) (plist-get page-info :position) "\n" (plist-get page-info :hightlight-current)))) (cl-defmethod pyim-page-info-format ((_style (eql minibuffer)) page-info) "将 PAGE-INFO 格式化为选词框中显示的字符串. 样式类似: +------------------------------------+ | [ni hao]: 1.你好 2.你号 ... (1/9) | +------------------------------------+" ;; 在 minibuffer 中显示 page 的时候,page 字符串直接插入到 minibuffer 现有的内 ;; 容中, 为了便于区分,在 page 后面添加一个显眼的字符。 (format "[%-15s%s]: %s(%s/%s) $ " (pyim-page-preview-create (plist-get page-info :scheme)) (if (plist-get page-info :assistant-enable) " (辅)" "") (pyim-page-menu-create (plist-get page-info :candidates) (plist-get page-info :position) nil (plist-get page-info :hightlight-current)) (plist-get page-info :current-page) (plist-get page-info :total-page))) (cl-defgeneric pyim-page-preview-create (scheme &optional separator) "这个函数用于创建在 page 中显示的预览字符串。 这个预览是在 page 中显示,而 `pyim-preview--refresh' 对应的预览 是在 buffer 光标处显示,两者要做区别。") (cl-defmethod pyim-page-preview-create ((_scheme pyim-scheme-quanpin) &optional separator) (let* ((separator (or separator " ")) (translated (string-join (mapcar (lambda (w) (concat (nth 0 w) (nth 1 w))) (pyim-process-get-first-imobj)) separator))) (concat ;; | 显示光标位置的字符 (pyim-process-with-entered-buffer (if (equal 1 (point)) (concat "|" translated) (concat (replace-regexp-in-string (concat separator "'") "'" translated) " |" (buffer-substring-no-properties (point) (point-max))))) ;; 使用辅助输入法时,在 page 中提示默认输入法的 code, 这个功能对形码用户挺 ;; 有用。 (pyim-page--code-hint-of-default-scheme)))) (defun pyim-page--code-hint-of-default-scheme () "获取当前词条在默认输入法下的 code 提示." (when (pyim-scheme-assistant-enable-p) (let* ((word (nth (pyim-process-word-position) (pyim-process-get-candidates))) (codes (sort (pyim-cstring-to-codes word (pyim-scheme-get pyim-default-scheme)) (lambda (a b) (< (length a) (length b))))) (hint (string-join codes " "))) (if (> (length hint) 0) (format " [%s]" hint) " ")))) (cl-defmethod pyim-page-preview-create ((scheme pyim-scheme-shuangpin) &optional separator) (let ((keymaps (pyim-scheme-shuangpin-keymaps scheme)) result) (dolist (w (pyim-process-get-first-imobj)) (let ((sm (nth 0 w)) (ym (nth 1 w))) (if (equal sm "") (push (car (rassoc (list ym) keymaps)) result) (push (concat (cl-some (lambda (x) (when (equal sm (nth 1 x)) (car x))) keymaps) (cl-some (lambda (x) (when (or (equal ym (nth 2 x)) (equal ym (nth 3 x))) (car x))) keymaps)) result)))) (string-join (reverse result) (or separator " ")))) (cl-defmethod pyim-page-preview-create ((_scheme pyim-scheme-xingma) &optional _separator) ;; | 显示光标位置的字符 (pyim-process-with-entered-buffer (if (equal (point) (point-max)) (buffer-substring-no-properties (point-min) (point-max)) (concat (buffer-substring-no-properties (point-min) (point)) "| " (buffer-substring-no-properties (point) (point-max)))))) (defun pyim-page-menu-create (candidates position &optional separator hightlight-current) "这个函数用于创建在 page 中显示的备选词条菜单。" (let ((i 0) result) (dolist (candidate candidates) (let ((str (substring-no-properties (if (consp candidate) (concat (car candidate) (cdr candidate)) candidate)))) (setq i (1+ i)) ;; 高亮当前选择的词条,用于 `pyim-page-next-word' (push (if (and hightlight-current (= i (+ position 1))) (format "%d%s" i (propertize (format "[%s]" str) 'face 'pyim-page-selection)) (format "%d.%s " i str)) result))) (string-join (nreverse result) (or separator "")))) (defun pyim-page-plan-to-select-word (num-key) "按照 NUM-KEY 预选词条,如果预选不成功,则返回 nil." (let ((index (if (numberp num-key) (- num-key 1) 0)) (end (pyim-page--end))) (when (= index -1) (setq index 9)) (when (<= (+ index (pyim-page--start)) end) (pyim-process-plan-to-select-word (+ (pyim-page--start) index))))) (defun pyim-page-next-page (arg) "Pyim page 翻页命令." (interactive "p") (if (pyim-process-without-entered-p) (pyim-process-select-last-char) (pyim-process-plan-to-select-word (pyim-page--start (pyim-process-next-word-position (* pyim-page-length arg)))) (pyim-process-ui-refresh))) (defun pyim-page-previous-page (arg) (interactive "p") (pyim-page-next-page (- arg))) (defun pyim-page-next-word (arg) (interactive "p") (if (pyim-process-without-entered-p) (pyim-process-select-last-char) (pyim-process-plan-to-select-word (pyim-process-next-word-position arg)) (pyim-process-ui-refresh 'hightlight-current))) (defun pyim-page-previous-word (arg) (interactive "p") (pyim-page-next-word (- arg))) (defun pyim-page--hide () "Hide pyim page." (pyim-page-hide-tooltip (pyim-page--get-valid-tooltip))) (cl-defgeneric pyim-page-hide-tooltip (tooltip) "Hide TOOLTIP.") (cl-defmethod pyim-page-hide-tooltip ((_tooltip (eql popup))) "Hide popup tooltip." (popup-delete pyim-page--popup)) (cl-defmethod pyim-page-hide-tooltip ((_tooltip (eql popon))) "Hide popon tooltip." (popon-kill pyim-page--popon)) (cl-defmethod pyim-page-hide-tooltip ((_tooltip (eql posframe))) "Hide posframe tooltip." (posframe-hide pyim-page--posframe-buffer)) (cl-defmethod pyim-page-hide-tooltip ((_tooltip (eql minibuffer))) "Hide minibuffer tooltip." (when (eq (selected-window) (minibuffer-window)) ;; 从 minibuffer 中删除 page 字符串。 (delete-char (length pyim-page--minibuffer-string)) ;; 在类似 vertico-posframe 这样的环境中,posframe window-point 同步问题 ;; 不太好处理,这里使用一个简单粗暴的方式:在输入过程中,隐藏真实的 ;; cursor 并显示一个伪 cursor, 输入完成之后再恢复。 (setq-local cursor-type t)) (setq pyim-page--minibuffer-string nil)) (add-hook 'pyim-process-ui-hide-hook #'pyim-page--hide) ;; * Footer (provide 'pyim-page) ;;; pyim-page.el ends here pyim-5.3.3/pyim-probe.el0000644000175000017500000002147514360352557014762 0ustar dogslegdogsleg;;; pyim-probe.el --- Auto-Switch-to-English-Input probes for pyim -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2015-2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;; * 使用说明 :doc: ;; ** 简介 ;; 这个文件包含了许多探针函数,用于实现两个功能: ;; 1. 根据环境自动切换到英文输入模式 ;; 2. 根据环境自动切换到半角标点输入模式 ;; ** 设置 ;; *** 根据环境自动切换到英文输入模式 ;; 用户将探针函数添加到 `pyim-english-input-switch-functions' 后, 就可以激活这个 ;; 探针函数,比如: ;; #+BEGIN_EXAMPLE ;; (setq-default pyim-english-input-switch-functions ;; '(pyim-probe-dynamic-english ;; pyim-probe-isearch-mode ;; pyim-probe-program-mode)) ;; #+END_EXAMPLE ;; 只要上述 *函数列表* 中,任意一个函数返回值为 t, pyim 就自动切换到 ;; 英文输入模式。 ;; *** 根据环境自动切换到半角标点输入模式 ;; 用户将探针函数添加到 `pyim-punctuation-half-width-functions' 后, 就可以激活这个 ;; 探针函数。 ;;; Code: ;; * 代码 :code: (require 'pyim-common) (require 'pyim-process) ;; ** 根据环境自动切换到英文输入模式 (defun pyim-probe-program-mode () "激活这个 pyim 探针函数后,只能在字符串和 comment 中输入中文。 注:仅仅影响 `prog-mode' 衍生的 mode 。 用于:`pyim-english-input-switch-functions' 。" (interactive) (when (derived-mode-p 'prog-mode) (let* ((pos (point)) (ppss (syntax-ppss pos))) (not (or (car (setq ppss (nthcdr 3 ppss))) (car (setq ppss (cdr ppss))) (nth 3 ppss)))))) (defvar org-heading-regexp) (defvar org-use-speed-commands) (defvar pyim-isearch-mode) (defvar isearch-mode) (defun pyim-probe-org-speed-commands () "激活这个 pyim 探针函数后,可以解决 org-speed-commands 与 pyim 冲突问题。 用于:`pyim-english-input-switch-functions' 。" (and (string= major-mode "org-mode") (bolp) (looking-at org-heading-regexp) org-use-speed-commands)) (defun pyim-probe-isearch-mode () "激活这个 pyim 探针函数后,使用 isearch 搜索时,禁用中文输入,强制英文输入。 用于:`pyim-english-input-switch-functions' 。" (and pyim-isearch-mode ;; isearch 启动的时候,会设置一个 buffer variable: `isearch-mode' ;; 检测所有 buffer 中 `isearch-mode' 的取值,如果任何一个 ;; 取值为 t, 就说明 isearch 已经启动。 (cl-some (lambda (buf) (buffer-local-value 'isearch-mode buf)) (buffer-list)))) (defun pyim-probe-org-structure-template () "激活这个 pyim 探针函数后,输入 org-structure-template 时,不会开启中文输入。 用于:`pyim-english-input-switch-functions' 。" (when (eq major-mode 'org-mode) (let ((line-string (buffer-substring (line-beginning-position) (point)))) (and (looking-at "[ \t]*$") (string-match "^[ \t]*<\\([a-zA-Z]*\\)$" line-string))))) (defun pyim-probe-dynamic-english () "激活这个 pyim 探针函数后,使用下面的规则动态切换中英文输入: 1. 从光标往前找第一个非数字的字符,为中文字符时,输入下一个字符时默认开启中文输入 2. 从光标往前找第一个非数字的字符,为其他字符时,输入下一个字符时默认开启英文输入 3. 使用 `pyim-convert-string-at-point' 可以将光标前的字符串转换为中文, 所以用户需要给 `pyim-convert-string-at-point' 绑定一个快捷键,比如: (global-set-key (kbd \"M-i\") #\\='pyim-convert-string-at-point) 这个函数用于:`pyim-english-input-switch-functions' 。" (let* ((offset 0) (non-digit-str-before-1 (pyim-char-before-to-string offset))) (while (and non-digit-str-before-1 (cl-search non-digit-str-before-1 "0123456789")) (cl-incf offset) (setq non-digit-str-before-1 (pyim-char-before-to-string offset))) (if (<= (point) (save-excursion (back-to-indentation) (point))) (not (or (pyim-string-match-p "\\cc" (save-excursion ;; 查找前一个非空格字符。 (if (re-search-backward "[^[:space:]\n]" nil t) (char-to-string (char-after (point)))))) (> (length (pyim-process-get-entered 'point-before)) 0))) (not (or (pyim-string-match-p "\\cc" non-digit-str-before-1) (> (length (pyim-process-get-entered 'point-before)) 0)))))) (defun pyim-probe-auto-english () "激活这个 pyim 探针函数后,使用下面的规则自动切换中英文输入: 1. 当前字符为英文字符(不包括空格)时,输入下一个字符为英文字符 2. 当前字符为中文字符或输入字符为行首字符时,输入的字符为中文字符 3. 以单个空格为界,自动切换中文和英文字符 即,形如 `我使用 emacs 编辑此函数' 的句子全程自动切换中英输入法 这个函数用于:`pyim-english-input-switch-functions' 。" (let ((str-before-1 (pyim-char-before-to-string 0)) (str-before-2 (pyim-char-before-to-string 1))) (if (> (point) (save-excursion (back-to-indentation) (point))) (or (if (pyim-string-match-p " " str-before-1) (pyim-string-match-p "\\cc" str-before-2) (and (not (pyim-string-match-p "\\cc" str-before-1)) (= (length (pyim-process-get-entered 'point-before)) 0))))))) (declare-function evil-normal-state-p "evil") (defun pyim-probe-evil-normal-mode () "判断是否是evil的normal模式,如果是则返回true. 这个函数用于:`pyim-english-input-switch-functions'." (evil-normal-state-p)) ;; ** 根据环境自动切换到半角标点输入模式 (defvar pyim-punctuation-dict) (defun pyim-probe-punctuation-line-beginning (char) "激活这个 pyim 探针函数后,行首输入标点时,强制输入半角标点。 用于:`pyim-punctuation-half-width-functions' 。" (let ((line-string (buffer-substring (line-beginning-position) (point)))) (and (member (char-to-string char) (mapcar #'car pyim-punctuation-dict)) (string-match "^[ \t]*$" line-string)))) (declare-function org-inside-LaTeX-fragment-p "org") (declare-function org-inside-latex-macro-p "org") (defun pyim-probe-punctuation-after-punctuation (char) "激活这个 pyim 探针函数后,半角标点后再输入一个标点符号时,强制输入半角标点。 用于:`pyim-punctuation-half-width-functions' 。" (let ((str-before-1 (pyim-char-before-to-string 0)) (puncts (mapcar #'car pyim-punctuation-dict))) (and (member str-before-1 puncts) (member (char-to-string char) puncts)))) (defun pyim-probe-org-latex-mode () "org-mode 中的 latex fragment 和 latex 宏指令中自动切换到英文输入." (and (eq major-mode 'org-mode) (or (org-inside-LaTeX-fragment-p) (org-inside-latex-macro-p)))) (defun pyim-probe-exwm-xim-environment () "测试当前是否是 exwm-xim 输入法环境。 这个探针主要用于: `pyim-force-input-chinese-functions'" (pyim-exwm-xim-environment-p)) (defvar xwidget-webkit-isearch--read-string-buffer) (defun pyim-probe-xwidget-webkit-environment () "测试当前是否是 xwidget-webkit 运行环境。 这个探针主要用于: `pyim-force-input-chinese-functions'." (or (eq this-original-command 'xwidget-webkit-pass-command-event-with-input-method) (bound-and-true-p xwidget-webkit-isearch--read-string-buffer))) (cl-pushnew #'pyim-probe-exwm-xim-environment pyim-force-input-chinese-functions) (cl-pushnew #'pyim-probe-xwidget-webkit-environment pyim-force-input-chinese-functions) ;; * Footer (provide 'pyim-probe) ;;; pyim-probe.el ends here pyim-5.3.3/pyim-candidates.el0000644000175000017500000003565714476561504015763 0ustar dogslegdogsleg;;; pyim-candidates.el --- candidates lib for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-common) (require 'pyim-dcache) (require 'pyim-codes) (require 'pyim-pymap) (require 'pyim-cregexp) (require 'pyim-cstring) (defgroup pyim-candidates nil "Candidates of pyim." :group 'pyim) (defcustom pyim-enable-shortcode t "启用输入联想词功能." :type 'boolean) (defcustom pyim-candidates-search-buffer-p t "是否从当前 buffer 搜索词条。 这个功能很好用,但偶尔会导致 pyim 卡顿。" :type 'boolean) (defcustom pyim-candidates-xingma-words-function #'pyim-candidates-xingma-words-default "形码输入法候选词列表生成函数。 如果形码输入法用户需要微调候选词词频,可以自定义这个函数。" :type 'function) ;; ** 获取备选词列表 (defun pyim-candidates--sort (candidates) "对 CANDIDATES 进行排序。" (pyim-dcache-sort-words candidates)) (cl-defgeneric pyim-candidates-get-chief (scheme &optional personal-words common-words) "PYIM 输入法第一位候选词的获取策略。") (cl-defmethod pyim-candidates-get-chief ((_scheme pyim-scheme-quanpin) &optional personal-words _common-words) "PYIM 输入法第一位候选词的获取通用策略。" (or ;; 最近输入的10个不同的词中出现一次以上。 (cl-find-if (lambda (word) (> (or (car (pyim-dcache-get word '(iword2count-recent-10-words))) 0) 1)) personal-words) ;; 最近输入的50个不同的词中出现过三次以上。 (cl-find-if (lambda (word) (> (or (car (pyim-dcache-get word '(iword2count-recent-50-words))) 0) 3)) personal-words) ;; 个人词条中的第一个词。 (car personal-words))) (cl-defgeneric pyim-candidates-create (imobjs scheme) "按照 SCHEME, 从 IMOBJS 获得候选词条。") (cl-defmethod pyim-candidates-create (imobjs (scheme pyim-scheme-xingma)) "按照 SCHEME, 从 IMOBJS 获得候选词条,用于五笔仓颉等形码输入法。" (let (result) (dolist (imobj imobjs) (let* ((codes (pyim-codes-create imobj scheme)) (last-code (car (last codes))) (other-codes (remove last-code codes)) output prefix) ;; 如果 wubi/aaaa -> 工 㠭;wubi/bbbb -> 子 子子孙孙;wubi/cccc 又 叕; ;; 用户输入为: aaaabbbbcccc ;; 那么: ;; 1. codes => ("wubi/aaaa" "wubi/bbbb" "wubi/cccc") ;; 2. last-code => "wubi/cccc" ;; 3. other-codes => ("wubi/aaaa" "wubi/bbbb") ;; 4. prefix => 工子 (when other-codes (setq prefix (mapconcat (lambda (code) (car (pyim-candidates-xingma-words code))) other-codes ""))) ;; 5. output => 工子又 工子叕 (setq output (mapcar (lambda (word) (concat prefix word)) (pyim-candidates-xingma-words last-code))) (setq output (remove "" (or output (list prefix)))) (setq result (append result output)))) (when (car result) (delete-dups result)))) (defun pyim-candidates-xingma-words (code) "搜索形码 CODE, 得到相应的词条列表。" (and (functionp pyim-candidates-xingma-words-function) (funcall pyim-candidates-xingma-words-function code))) (defun pyim-candidates-xingma-words-default (code) "搜索形码 CODE, 得到相应的词条列表。 当前的词条的构建规则是: 1. 先排公共词库中的字。 2. 然后再排所有词库中的词,词会按词频动态调整。" (let* ((common-words (pyim-dcache-get code '(code2word))) (common-chars (pyim-candidates--get-chars common-words)) (personal-words (pyim-dcache-get code '(icode2word))) (other-words (pyim-dcache-get code '(shortcode2word))) (words-without-chars (pyim-candidates--sort (pyim-candidates--remove-chars (delete-dups `(,@personal-words ,@common-words ,@other-words)))))) `(,@common-chars ,@words-without-chars))) (defun pyim-candidates--get-chars (words) "从 WORDS 中获取字。" (cl-remove-if (lambda (x) (> (length x) 1)) words)) (defun pyim-candidates--remove-chars (words) "把 WORDS 中的字删除。" (cl-remove-if (lambda (x) (< (length x) 2)) words)) (cl-defmethod pyim-candidates-create (imobjs (scheme pyim-scheme-quanpin)) "按照 SCHEME, 从 IMOBJS 获得候选词条,用于全拼输入法。" ;; 这段代码主要实现以下功能:假如用户输入 nihaomazheshi, 但词库里面找不到对 ;; 应的词条,那么输入法自动用 nihaoma 和 zheshi 的第一个词条:"你好吗" 和 " ;; 这是" 连接成一个新的字符串 "你好吗这是" 做为第一个候选词。 (let* ((candidates (pyim-candidates--quanpin imobjs scheme)) (n (length (car candidates))) output) (push (car candidates) output) (while (and (> n 0) (car (setq imobjs (mapcar (lambda (imobj) (nthcdr n imobj)) imobjs)))) (let ((candidates (pyim-candidates--quanpin imobjs scheme))) (push (car (pyim-candidates--quanpin imobjs scheme t)) output) (setq n (length (car candidates))))) (append (pyim-subconcat (nreverse output) "") candidates))) (defun pyim-candidates--quanpin (imobjs scheme &optional fast-search) "用于全拼输入法的 `pyim-candidates-create' 方法内部使用的函数。" (let* ((znabc-words (pyim-candidates--znabc-words imobjs scheme fast-search)) (jianpin-words (pyim-candidates--jianpin-words imobjs scheme fast-search)) (quanpin-words (pyim-candidates--quanpin-words imobjs scheme fast-search)) (personal-words (pyim-candidates--sort (nth 0 quanpin-words))) (common-words (nth 1 quanpin-words)) (chief-word (pyim-candidates-get-chief scheme personal-words)) (quanpin-chars (pyim-candidates--quanpin-first-chars imobjs scheme fast-search)) (matched-chars (nth 0 quanpin-chars)) (possible-chars (nth 1 quanpin-chars)) (words `( :chief-word ,chief-word :personal-words ,@personal-words :jianpin-words ,@jianpin-words :common-words ,@common-words :znabc-words ,@znabc-words :matched-chars ,@matched-chars :possible-chars ,@possible-chars))) (when pyim-debug (print words)) (delete-dups (cl-remove-if-not #'stringp words)))) (defun pyim-candidates--znabc-words (imobjs scheme &optional fast-search) "智能ABC模式,得到尽可能的拼音组合,查询这些组合,得到的词条做为联想词。" (let ((codes (mapcar (lambda (x) (pyim-subconcat x "-")) (mapcar (lambda (imobj) (pyim-codes-create imobj scheme)) imobjs)))) (pyim-zip (mapcar #'pyim-dcache-get (pyim-zip codes)) fast-search))) (defun pyim-candidates--jianpin-words (imobjs scheme &optional fast-search) "获取简拼词语。 假如输入 \"nih\" ,那么搜索 code 为 \"n-h\" 的词条,然后筛选出所 有拼音匹配\"ni-h\" 或者 \"ni[^-]*-h\" 的词条。" (when (and pyim-enable-shortcode (> (length (car imobjs)) 1)) (let (jianpin-words) (dolist (imobj imobjs) (let* ((w (pyim-dcache-get (string-join (pyim-codes-create imobj scheme 1) "-") '(ishortcode2word))) (regexp1 (string-join (pyim-codes-create imobj scheme) "-")) (regexp2 (string-join (pyim-codes-create imobj scheme) "[^-]*-")) (w1 (cl-remove-if-not (lambda (cstr) (let ((py (pyim-cstring-to-pinyin cstr nil "-"))) (or (string-match-p regexp1 py) (string-match-p regexp2 py)))) w)) (w2 (cl-remove-if-not (lambda (cstr) (string-match-p regexp1 (pyim-cstring-to-pinyin cstr nil "-"))) w1))) (push (delete-dups (append w2 w1)) jianpin-words))) (pyim-zip (nreverse jianpin-words) fast-search)))) (defun pyim-candidates--quanpin-words (imobjs scheme &optional fast-search) "从 dcache 获取个人词条,词库词条。" (let (personal-words common-words) (dolist (imobj imobjs) (let* ((w1 (pyim-candidates--quanpin-personal-words imobj scheme)) (w2 (pyim-candidates--quanpin-common-words imobj scheme))) (push w1 personal-words) (push w2 common-words))) (setq personal-words (pyim-zip (nreverse personal-words) fast-search)) (setq common-words (pyim-zip (nreverse common-words) fast-search)) (list personal-words common-words))) (defun pyim-candidates--quanpin-personal-words (imobj scheme) (pyim-dcache-get (string-join (pyim-codes-create imobj scheme) "-") (if pyim-enable-shortcode '(icode2word ishortcode2word) '(icode2word)))) (defun pyim-candidates--quanpin-common-words (imobj scheme) (pyim-dcache-get (string-join (pyim-codes-create imobj scheme) "-") (if pyim-enable-shortcode '(code2word shortcode2word) '(code2word)))) (defun pyim-candidates--quanpin-first-chars (imobjs scheme &optional fast-search) "获取词条第一汉字列表。" (let (matched-chars possible-chars) (dolist (imobj imobjs) (let* ((w1 (pyim-candidates--quanpin-first-matched-chars imobj scheme)) (w2 (unless w1 (pyim-candidates--quanpin-first-possible-chars imobj scheme)))) (push w1 matched-chars) (push w2 possible-chars))) (setq matched-chars (pyim-zip (nreverse matched-chars) fast-search)) (setq possible-chars (pyim-zip (nreverse possible-chars) fast-search)) (list matched-chars possible-chars))) (defun pyim-candidates--quanpin-first-matched-chars (imobj scheme) "获取输入的全拼对应的第一个汉字。 假如用户输入 nihao 时,获取 ni 对应的汉字。" (let ((code (car (pyim-codes-create imobj scheme)))) (delete-dups `(,@(pyim-dcache-get code '(icode2word code2word)) ,@(pyim-pymap-py2cchar-get code t t))))) (defun pyim-candidates--quanpin-first-possible-chars (imobj scheme) "获取输入的全拼对应的第一个可能的常用汉字。 假如用户输入 ni 时,获取拼音匹配 ni.* 的常用汉字,比如:ni niao ning niu 等等。" (let ((pinyin (car (pyim-codes-create imobj scheme)))) (mapcar #'char-to-string (pyim-zip (mapcar (lambda (x) ;; NOTE: 这里只取最常用的汉字,太多的汉字会带 ;; 来后续处理压力,可能拖慢输入法。不过这个结 ;; 论只是猜测。 (car (split-string x "|"))) (pyim-pymap-py2cchar-get pinyin nil 1)))))) (cl-defgeneric pyim-candidates-create-limit-time (_imobjs _scheme) "按照 SCHEME, 使用限时运行的方式从 IMOBJS 获得候选词条。 1. 这个函数是同步运行。 2. 这个函数运行有时间限制,运行超过某个时间后,无论有没有结果,必须结束。 3. 这个函数需要探测用户是否输入,如果用户开始输入,这个函数运行必须结束。" nil) (cl-defmethod pyim-candidates-create-limit-time (imobjs (scheme pyim-scheme-quanpin)) "按照 SCHEME, 用限时运行的方式从 IMOBJS 获得候选词条,用于全拼输入法。" ;; 构建一个搜索中文的正则表达式, 然后使用这个正则表达式在当前 buffer 中搜 ;; 索词条。 (let ((str (string-join (pyim-codes-create (car imobjs) scheme)))) (when (and pyim-candidates-search-buffer-p (> (length str) 0)) (pyim-candidates--search-buffer (pyim-cregexp-create str scheme 3 t))))) (defun pyim-candidates--search-buffer (regexp) "在当前 buffer 中使用 REGEXP 搜索词条。" (when (not (input-pending-p)) ;只有在用户输入停顿的时候才搜索 buffer. (save-excursion (let ((counts (make-hash-table :test #'equal)) (time-limit 0.1) words) (goto-char (point-min)) (pyim-time-limit-while (and (not (input-pending-p)) ;如果用户继续输入,就停止 buffer 搜索。 (re-search-forward regexp nil t)) time-limit (let* ((match (match-string-no-properties 0)) (word (propertize match :comment "(buf)"))) ;; NOTE: 单个汉字我觉得不值得收集。 (when (>= (length word) 2) (if (member word words) (cl-incf (gethash word counts)) (push word words) (puthash word 1 counts))))) (sort words (lambda (a b) (> (or (gethash a counts) 0) (or (gethash b counts) 0)))))))) (cl-defmethod pyim-candidates-create-limit-time (imobjs (_scheme pyim-scheme-shuangpin)) "按照 SCHEME, 用限时运行的方式从 IMOBJS 获得候选词条,用于双拼输入法。" ;; 注意:pyim 支持的双拼输入法,内部使用全拼的 imobjs, 所以这里直接调用全拼的 ;; `pyim-candidates-create-limit-time' 方法来处理 imobjs。 (pyim-candidates-create-limit-time imobjs (pyim-scheme-get 'quanpin))) (cl-defgeneric pyim-candidates-create-async (_imobjs _scheme _callback) "按照 SCHEME, 使用异步的方式从 IMOBJS 获得候选词条。 获取到的词条后,需要将其做为参数,调用 CALLBACK 函数。" nil) ;; * Footer (provide 'pyim-candidates) ;;; pyim-candidates.el ends here pyim-5.3.3/pyim-dict.el0000644000175000017500000000621014412763713014562 0ustar dogslegdogsleg;;; pyim-dict.el --- Dict core tools for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (defgroup pyim-dict nil "Dict tools for pyim." :group 'pyim) (defcustom pyim-dicts nil "一个列表,用于保存 `pyim' 的词库信息. 每一个 element 都代表一条词库的信息, 用户可以使用词库管理命令 `pyim-dicts-manager' 来添加词库信息,每一条词库信息都使用一个 plist 来表示,比如: (:name \"100万大词库\" :file \"/path/to/pinyin-bigdict.pyim\") 其中: 1. `:name' 代表词库名称,用户可以按照喜好来确定(可选项)。 2. `:file' 表示词库文件, 另外一个与这个变量功能类似的变量是: `pyim-extra-dicts', 专门 用于和 elpa 格式的词库包集成。" :type '(repeat (plist :key-type (choice (const :tag "词库名称" :name) (const :tag "词库文件" :file)) :value-type string))) (defvar pyim-extra-dicts nil "类似 `pyim-dicts', 不过这个变量主要用于 elpa 词库包。 不建议用户手工设置这个变量。") (defun pyim-extra-dicts-add-dict (new-dict) "将 NEW-DICT 添加到 `pyim-extra-dicts'. 其中 NEW-DICT 的格式为: (:name \"XXX\" :file \"/path/to/XXX.pyim\") 这个函数主要用于 elpa 词库包 ,不建议普通用户使用。" (let (replace result) (dolist (dict pyim-extra-dicts) (if (equal (plist-get dict :name) (plist-get new-dict :name)) (progn (push new-dict result) (setq replace t)) (push dict result))) (setq result (reverse result)) (setq pyim-extra-dicts (if replace result `(,@result ,new-dict))) (message "PYIM: Add dict %S to `pyim-extra-dicts'." (plist-get new-dict :name)) t)) (defun pyim-dict-get-enabled-dict-files () "获取所有已经启用的 dict 文件。" (delete nil (mapcar (lambda (x) (unless (plist-get x :disable) (plist-get x :file))) `(,@pyim-dicts ,@pyim-extra-dicts)))) ;; * Footer (provide 'pyim-dict) ;;; pyim-dict.el ends here pyim-5.3.3/pyim-autoselector.el0000644000175000017500000000562414255423170016353 0ustar dogslegdogsleg;;; pyim-autoselector.el --- autoselector for pyim. -*- lexical-binding: t; -*- ;; * Header ;; Copyright (C) 2021 Free Software Foundation, Inc. ;; Author: Feng Shu ;; Maintainer: Feng Shu ;; URL: https://github.com/tumashu/pyim ;; Keywords: convenience, Chinese, pinyin, input-method ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: ;; * 代码 :code: (require 'cl-lib) (require 'pyim-scheme) (require 'pyim-process) (defgroup pyim-autoselector nil "Autoselector for pyim." :group 'pyim) (defun pyim-autoselector-xingma (&rest _args) "适用于型码输入法的自动上屏器. 比如:五笔等型码输入法,重码率很低,90%以上的情况都是选择第一个词 条,自动选择可以减少按空格强制选词的机会。" (let* ((scheme (pyim-scheme-current)) (split-length (pyim-scheme-xingma-code-split-length scheme)) (entered (pyim-process-get-entered 'point-before)) (candidates (pyim-process-get-candidates)) (last-candidates (pyim-process-get-last-candidates))) (when (pyim-scheme-xingma-p scheme) (pyim-autoselector--xingma split-length entered candidates last-candidates)))) (defun pyim-autoselector--xingma (split-length entered candidates last-candidates) "`pyim-autoselector-xingma' 内部使用的函数。" (cond ((and (= (length entered) split-length) (= (length candidates) 1) ;; 如果没有候选词,pyim 默认将用户输入当做候选词,这时不能自动上屏, ;; 因为这种情况往往是用户输入有误,自动上屏之后,调整输入就变得麻烦了。 (not (equal entered (car candidates)))) '(:select current)) ((and (> (length entered) split-length) (equal (substring entered 0 split-length) (car last-candidates))) ;; 自动清除错误输入模式,类似微软五笔:敲第五个字母的时候,前面四个字母自 ;; 动清除。 '(:select last :replace-with "")) ((> (length entered) split-length) '(:select last)) (t nil))) (cl-pushnew #'pyim-autoselector-xingma pyim-process-autoselector) ;; * Footer (provide 'pyim-autoselector) ;;; pyim-autoselector.el ends here