使ivy-read支持拼音搜索


#1

我给swiper提了这样一个issue。

据abo-abo的回复,这样搞定的:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 让`ivy-read'支持拼音
(require 'pinyinlib)

(defun re-builder-pinyin (str)
  (or (pinyin-to-utf8 str)
      (ivy--regex-plus str)
      (ivy--regex-ignore-order)
      ))

(setq ivy-re-builders-alist
      '(
        (t . re-builder-pinyin)
        ))

(defun my-pinyinlib-build-regexp-string (str)
  (progn
    (cond ((equal str ".*")
         ".*")
        (t
         (pinyinlib-build-regexp-string str t))))
  )
(defun my-pinyin-regexp-helper (str)
  (cond ((equal str " ")
         ".*")
        ((equal str "")
         nil)
        (t
         str)))

(defun pinyin-to-utf8 (str)
  (cond ((equal 0 (length str))
         nil)
        ((equal (substring str 0 1) "!")
         (mapconcat 'my-pinyinlib-build-regexp-string
                    (remove nil (mapcar 'my-pinyin-regexp-helper (split-string
                                                                  (replace-in-string str "!" "") "")))
                    ""))
        nil))

;; ;; ;;; 这样就可以去掉`pinyin'区配
;; (defun pinyin-to-utf8 (str)
;;   nil)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

前提是需要安装 pinyinlib 这个库。

这样的话,使用ivy-read的函数可以这样来match拼音:

!nh

就可以match到“你好”。

以"!"开头就开启区配拼音。否则还和原来的功能一样。

可以不用切换输入法啦 :slight_smile:


#2

朋友,我试过您的代码 ,但出现如下错误

Error in post-command-hook (ivy–exhibit): (void-function replace-in-string)

请问如何解决?谢谢!


#3

replace-in-string这个函数没有找到。查了一下我当前使用的代码中没有用这个函数。是使用的 replace-regexp-in-string。不知道怎么回事,我发现我不好修改本帖原来的代码。把当前我正在使用的代码重贴一下你再试试?

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 让`ivy-read'支持拼音
(require 'pinyinlib)
(defun my-pinyinlib-build-regexp-string (str)
  (progn
    (cond ((equal str ".*")
           ".*")
          (t
           (pinyinlib-build-regexp-string str t))))
  )
(defun my-pinyin-regexp-helper (str)
  (cond ((equal str " ")
         ".*")
        ((equal str "")
         nil)
        (t
         str)))

(defun pinyin-to-utf8 (str)
  (cond ((equal 0 (length str))
         nil)
        ((equal (substring str 0 1) ":")
         (mapconcat 'my-pinyinlib-build-regexp-string
                    (remove nil (mapcar 'my-pinyin-regexp-helper (split-string
                                                                  (replace-regexp-in-string ":" "" str ) "")))
                    ""))
        nil))

;;; 这是我自定义的匹配策略
(defun re-builder-pinyin (str)
  (or (pinyin-to-utf8 str)
      (ivy--regex-plus str)))

(setq ivy-re-builders-alist
      '((t . re-builder-pinyin)))

对了,我把打开拼音区配的前缀改成了 : 。所以区匹配你好可以这样:

:nh

#4

cool, 顺便提一句, 如果使用pyim的话, 也可以使用 pyim-cregexp-build 来创建搜索中文的regexp :slight_smile: , 和 pinyinlib-build-regexp-string 的作用类似


#5

我自己用的一个简单版本,不过依赖 pyim

(use-package pyim
  :after ivy
  :config

  (defun eh-ivy-cregexp (str)
    (if (string-match-p "^\\." str)
        (pyim-cregexp-build (substring str 1))
      (ivy--regex-plus str)))

  (setq ivy-re-builders-alist
        '((t . eh-ivy-cregexp))))

#6

这个版本的更加好用,中英文同时搜索

(use-package pyim
  :after ivy
  :config

  (defun eh-ivy-cregexp (str)
    (concat
     (ivy--regex-plus str)
     "\\|"
     (pyim-cregexp-build str)))

  (setq ivy-re-builders-alist
        '((t . eh-ivy-cregexp))))

#7

用这个设置会导致swiper在搜索一些字符时出错,比如说P,错误信息如下 (ivy–queue-exhibit): (args-out-of-range “” -1 nil)


#8

你应该提供更多的可重现错误的上下文


#9

超 好 的 啦


#10

历害了。不过我习惯了用eim的五笔,也就没装pyim。后面有机会试下。:slight_smile: