3

I need to check whether a string is spelled correctly from my ELisp code. This is what I am trying:

(ispell-start-process)
(ispell-send-string "Check this")
(ispell-accept-output)

The last call freezes, although an ispell process seems to be running, since (ispell-process-status) returns 'run and Fly-Spell is working properly (though in a different buffer). All I need is a boolean result showing whether a given string is spelled correctly or not. How do I achieve this?

3 Answers 3

1

The following is an adaption of ispell-word. It also allows to specify the dictionary for the spell checking of the string.

(require 'ispell)

(defun ispell-string (string &optional dictionary quietly)
  "Ispell STRING with DICTIONARY.
DICTIONARY defaults to `ispell-local-dictionary' if that is set in the current buffer
and to `ispell-dictionary' otherwise.
Non-nil QUIETLY supresses messages about correct and incorrect spelling."
  (interactive (list (read-string "String to be checked:")
             (completing-read
              "Use new dictionary (RET for current, SPC to complete): "
              (and (fboundp 'ispell-valid-dictionary-list)
               (mapcar 'list (ispell-valid-dictionary-list))))))
  (let ((ispell-local-dictionary (or (and (stringp dictionary)
                      (> (length dictionary) 0)
                      dictionary)
                     ispell-local-dictionary)))
    (ispell-set-spellchecker-params)  ; Initialize variables and dicts alists
    (ispell-accept-buffer-local-defs) ; Accepts ispell-local-dictionary.
    ;; ... Word extraction from `ispell-word' deleted.
    ;; At this point it used to ignore 2-letter words.
    ;; But that is silly; if the user asks for it, we should do it. - rms.
    (cl-every 'identity
     (mapcar
      (lambda (word)
    (ispell-init-process) ;< Additional to the stuff from `ispell-word'.
    (or quietly
        (message "Checking spelling of %s..."
             (funcall ispell-format-word-function word)))
    (ispell-send-string "%\n")  ; put in verbose mode
    (ispell-send-string (concat "^" word "\n"))
    ;; wait until ispell has processed word
    (while (progn
         (ispell-accept-output)
         (not (string= "" (car ispell-filter)))))
    ;;(ispell-send-string "!\n") ;back to terse mode.
    (setq ispell-filter (cdr ispell-filter)) ; remove extra \n
        (let (poss)
          (if (and ispell-filter (listp ispell-filter))
              (if (> (length ispell-filter) 1)
                  (error "Ispell and its process have different character maps")
                (setq poss (ispell-parse-output (car ispell-filter)))))
          (let ((ret (eq poss t)))
            (unless quietly
              (message "%s is %scorrect"
                       (funcall ispell-format-word-function word)
                       (or (and ret "") "in")))
            ret)))
        (split-string string "[^[:alpha:]]" t "[^[:alpha:]]")))))
2
  • Does it check the whole string or only the last word in the string (in which case the name of the function is misleading)? My answer would only check the last word and I don't see much difference in how the two answers operate. Dec 16, 2017 at 20:40
  • @AlwaysLearning You have a point. I've corrected the lisp code such that the whole string is checked. Thanks for the comment.
    – Tobias
    Dec 16, 2017 at 21:02
0

Adapted from https://codegists.com/code/helm%20flyspell%20correct/, it prints OK when word is correct and wrong when word is incorrect:

(ispell-start-process)
(ispell-send-string "hello\n")

(while (progn
     (accept-process-output ispell-process)
     (not (string= "" (car ispell-filter)))))
;; Remove leading empty element
(setq ispell-filter (cdr ispell-filter))
;; ispell process should return something after word is sent.
;; Tag word as valid (i.e., skip) otherwise
(or ispell-filter
    (setq ispell-filter '(*)))
(if (consp ispell-filter)
    (setq poss (ispell-parse-output (car ispell-filter))))
(cond
 ((or (eq poss t) (stringp poss))
  ;; don't correct word
  (message "OK"))
 ((null poss)
  ;; ispell error
  (error "Ispell: error in Ispell process"))
 (t
  (error "wrong")))

EDIT:

Note that this not a function, this is just a piece of code. Replace hello\n with whatever you want.

7
  • I made this code into a function and called the function. First it correctly says "OK". Then I change the word to something wrong and re-evaluate. When I invoke the function it correctly errors "wrong". However, when I change it back to "hello\n" (and re-evaluate), it continues to say "wrong". That is, once this code errors "wrong" once, I cannot cause it to say "OK" anymore. Dec 16, 2017 at 19:03
  • Can you post the function's code? Dec 16, 2017 at 19:05
  • I put this code into a new buffer, saved it, ran eval-buffer and it said OK, I replaced hello with helloo, saved it, ran eval-buffer again and it said wrong, I replaced helloo back to hello, saved it, ran eval-buffer and it said OK. Can you confirm it also works for you? Dec 16, 2017 at 19:10
  • I did what you did, but it said wrong when I changed it back to hello... Dec 16, 2017 at 19:41
  • I have no clue. What emacs version do you have? What OS? Dec 16, 2017 at 19:47
0

The code in the answer of @Arkadiusz Drabczyk is adapted from flyspell-correct-word-before-point. That function works, so I re-worked it into what I need:

(defun check-word(word)
  (let (poss ispell-filter)
    (ispell-send-string "%\n")  ;put in verbose mode
    (ispell-send-string (concat "^" word "\n"))
    ;; wait until ispell has processed word
    (while (progn
         (accept-process-output ispell-process)
         (not (string= "" (car ispell-filter)))))
    ;; Remove leading empty element
    (setq ispell-filter (cdr ispell-filter))
    ;; ispell process should return something after word is sent.
    ;; Tag word as valid (i.e., skip) otherwise
    (or ispell-filter
    (setq ispell-filter '(*)))
    (if (consp ispell-filter)
    (setq poss (ispell-parse-output (car ispell-filter))))
    (cond
     ((or (eq poss t) (stringp poss))
      ;; The word is correct.
      t)
     ((null poss)
      ;; ispell error
      (error "Ispell: error in Ispell process"))
     (t
      ;; The word is incorrect.
      nil))))
2
  • I am glad it works for you. Please mark this answer as accepted for other users know your problem is solved. Dec 16, 2017 at 20:21
  • The policy of having to wait for some 14 hours before accepting makes it difficult not to forget... Dec 16, 2017 at 20:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.