Использование ispell / aspell для проверки правописания слов на верблюдах - PullRequest
8 голосов
/ 24 августа 2010

Мне нужно проверить орфографию большого документа, содержащего много слов на верблюжьих словах.Я хочу, чтобы ispell или aspell проверили, правильно ли написаны отдельные слова.

Итак, в случае этого слова:

ScientificProgrezGoesBoink

Я бы хотел, чтобы оно предложило вместо этого:

ScientificProgressGoesBoink

Есть ли способ сделать это?(И я имею в виду, при запуске его в буфере Emacs.) Обратите внимание, что я не обязательно хочу предлагать полную альтернативу.Однако, если он понимает, что Progrez не распознается, я бы хотел хотя бы заменить эту часть или добавить это слово в свой личный словарь, а не включать каждое слово в верблюжьей оболочке в словарь.

Ответы [ 3 ]

3 голосов
/ 25 февраля 2011

Я принял предложения @phils и покопался немного глубже.Оказывается, что если вы получаете camelCase-mode и перенастраиваете некоторые из ispell следующим образом:

(defun ispell-get-word (following)
  (when following
    (camelCase-forward-word 1))
  (let* ((start (progn (camelCase-backward-word 1)
                       (point)))
         (end (progn (camelCase-forward-word 1)
                     (point))))
    (list (buffer-substring-no-properties start end)
          start end)))

, то в этом случае отдельные слова в верблюжьих словах suchAsThisOne на самом деле будет проверено орфография правильно.(Если вы не в начале документа - я только что узнал.)

Так что это явно не полноценное решение, но, по крайней мере, это что-то.

2 голосов
/ 22 июля 2014

В aspell есть опция --run-Together.Hunspell не может проверить слово на верблюде. ​​

Если вы прочтете код aspell, вы обнаружите, что его алгоритм фактически не разбивает слово верблюжьей слуги на список подслов.Возможно, этот алгоритм работает быстрее, но он неверно сообщит слово, содержащее двухсимвольное подслово, как опечатку.Не тратьте время, чтобы настроить другие варианты Aspell.Я пытался, и они не работали.

Итак, у нас есть две проблемы:

  1. aspell сообщает НЕКОТОРЫЕ слова на верблюжьих словах как опечатки

  2. hunspell сообщает ВСЕ слова на верблюдах как опечатки

Решение для ОБА проблем - написать собственный предикат на Emacs Lisp.

Вот пример предиката, написанного для javascript:

(defun split-camel-case (word)
  "Split camel case WORD into a list of strings.
Ported from 'https://github.com/fatih/camelcase/blob/master/camelcase.go'."
  (let* ((case-fold-search nil)
         (len (length word))
         ;; ten sub-words is enough
         (runes [nil nil nil nil nil nil nil nil nil nil])
         (runes-length 0)
         (i 0)
         ch
         (last-class 0)
         (class 0)
         rlt)

    ;; split into fields based on class of character
    (while (< i len)
      (setq ch (elt word i))
      (cond
       ;; lower case
       ((and (>= ch ?a) (<= ch ?z))
        (setq class 1))
       ;; upper case
       ((and (>= ch ?A) (<= ch ?Z))
        (setq class 2))
       ((and (>= ch ?0) (<= ch ?9))
        (setq class 3))
       (t
        (setq class 4)))

      (cond
       ((= class last-class)
        (aset runes
              (1- runes-length)
              (concat (aref runes (1- runes-length)) (char-to-string ch))))
       (t
        (aset runes runes-length (char-to-string ch))
        (setq runes-length (1+ runes-length))))
      (setq last-class class)
      ;; end of while
      (setq i (1+ i)))

    ;; handle upper case -> lower case sequences, e.g.
    ;;     "PDFL", "oader" -> "PDF", "Loader"
    (setq i 0)
    (while (< i (1- runes-length))
      (let* ((ch-first (aref (aref runes i) 0))
             (ch-second (aref (aref runes (1+ i)) 0)))
        (when (and (and (>= ch-first ?A) (<= ch-first ?Z))
                   (and (>= ch-second ?a) (<= ch-second ?z)))
          (aset runes (1+ i) (concat (substring (aref runes i) -1) (aref runes (1+ i))))
          (aset runes i (substring (aref runes i) 0 -1))))
      (setq i (1+ i)))

    ;; construct final result
    (setq i 0)
    (while (< i runes-length)
      (when (> (length (aref runes i)) 0)
        (setq rlt (add-to-list 'rlt (aref runes i) t)))
      (setq i (1+ i)))
     rlt))

(defun flyspell-detect-ispell-args (&optional run-together)
  "If RUN-TOGETHER is true, spell check the CamelCase words.
Please note RUN-TOGETHER will make aspell less capable. So it should only be used in prog-mode-hook."
  ;; force the English dictionary, support Camel Case spelling check (tested with aspell 0.6)
  (let* ((args (list "--sug-mode=ultra" "--lang=en_US"))args)
    (if run-together
        (setq args (append args '("--run-together" "--run-together-limit=16"))))
    args))

;; {{ for aspell only, hunspell does not need setup `ispell-extra-args'
(setq ispell-program-name "aspell")
(setq-default ispell-extra-args (flyspell-detect-ispell-args t))
;; }}

;; ;; {{ hunspell setup, please note we use dictionary "en_US" here
;; (setq ispell-program-name "hunspell")
;; (setq ispell-local-dictionary "en_US")
;; (setq ispell-local-dictionary-alist
;;       '(("en_US" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "en_US") nil utf-8)))
;; ;; }}

(defvar extra-flyspell-predicate '(lambda (word) t)
  "A callback to check WORD.  Return t if WORD is typo.")

(defun my-flyspell-predicate (word)
  "Use aspell to check WORD.  If it's typo return t."
  (let* ((cmd (cond
               ;; aspell: `echo "helle world" | aspell pipe`
               ((string-match-p "aspell$" ispell-program-name)
                (format "echo \"%s\" | %s pipe"
                        word
                        ispell-program-name))
               ;; hunspell: `echo "helle world" | hunspell -a -d en_US`
               (t
                (format "echo \"%s\" | %s -a -d en_US"
                        word
                        ispell-program-name))))
         (cmd-output (shell-command-to-string cmd))
         rlt)
    ;; (message "word=%s cmd=%s" word cmd)
    ;; (message "cmd-output=%s" cmd-output)
    (cond
     ((string-match-p "^&" cmd-output)
      ;; it's a typo because at least one sub-word is typo
      (setq rlt t))
     (t
      ;; not a typo
      (setq rlt nil)))
    rlt))

(defun js-flyspell-verify ()
  (let* ((case-fold-search nil)
         (font-matched (memq (get-text-property (- (point) 1) 'face)
                             '(js2-function-call
                               js2-function-param
                               js2-object-property
                               js2-object-property-access
                               font-lock-variable-name-face
                               font-lock-string-face
                               font-lock-function-name-face
                               font-lock-builtin-face
                               rjsx-text
                               rjsx-tag
                               rjsx-attr)))
         subwords
         word
         (rlt t))
    (cond
     ((not font-matched)
      (setq rlt nil))
     ;; ignore two character word
     ((< (length (setq word (thing-at-point 'word))) 2)
      (setq rlt nil))
     ;; handle camel case word
     ((and (setq subwords (split-camel-case word)) (> (length subwords) 1))
      (let* ((s (mapconcat (lambda (w)
                             (cond
                              ;; sub-word wholse length is less than three
                              ((< (length w) 3)
                               "")
                               ;; special characters
                              ((not (string-match-p "^[a-zA-Z]*$" w))
                               "")
                              (t
                               w))) subwords " ")))
        (setq rlt (my-flyspell-predicate s))))
     (t
      (setq rlt (funcall extra-flyspell-predicate word))))
    rlt))

(put 'js2-mode 'flyspell-mode-predicate 'js-flyspell-verify)

Или просто используйте мой новый пакетик https://github.com/redguardtoo/wucuo

0 голосов
/ 24 августа 2010

Вы должны разобрать слова в верблюжьей оболочке и разбить их, затем проверить индивидуальное написание для каждого и собрать предложение, принимая во внимание единственное предложение для каждого маркера с ошибкой.Учитывая, что у каждого маркера с ошибкой может быть несколько предложений, это звучит немного неэффективно для меня.

...