3

For example suppose that I would like to show the message "yes" if the current character is "a" or "d" or "x", .... Of course I can write as below. But it is very long. I am wondering if there is a more simple way to do it. In this example the variable is char-after and the set is {a,d,x}. The problem can arise in other situation.

  (defun foo () (interactive)
    (if (or (eq (char-after) ?a ) (eq (char-after) ?d ) (eq (char-after) ?x )) 
    (message "yes") (message "no")))       
7

Here you go:

(defun foo ()
  (interactive)
  (if (memq (char-after) '(?a ?d ?x))
      (message "yes")
    (message "no")))

memq is possible because characters are numbers that can be compared with eq. If you want strings or lists, use member, which uses equal for comparison.

4

I like pcase a lot, though it may be slower in some cases.

(defun foo ()
  (interactive)
  (message
   (pcase (char-after)
      ((or ?a ?d ?x) "yes")
      (t "no"))))
  • You'll get a message when compiling this: Pattern t is deprecated. Use `_' instead. By the way, it's not slower in this case, it produces the same memq as abo-abo's answer. – npostavs 44 mins ago
2

For the sake of alternatives, first of all, since you are looking to test against a number of different characters, it looks like a regular expression would do the job more succinctly and, perhaps even faster (really depends on how many characters there will be to test from etc.)


Another way is to use char-table - a built-in Emacs data-structure for working with characters. Below is an example followed by explanation:

(defun char-handler () (message "I am char-handler"))
(defun special-handler () (message "I am special-handler"))

(defvar test-char-table (make-char-table 'testing 'char-handler))

(set-char-table-range test-char-table ?a 'special-handler)
(funcall (char-table-range test-char-table '?a))
"I am special-handler"
(funcall (char-table-range test-char-table '?b))
"I am char-handler"

make-char-table creates a sparse array-like structure where keys are characters and the values are whatever you want, but usually symbols pointing to some function. This data-structure is specifically designed to handle text processing so it should be reasonably fast, but, most importantly, it scales better with more handlers. It's dynamic (which means that adding or removing handlers is possible while without changing the rest of the code which uses relies on the function using it.

When you call set-char-table-range you can also provide things other than single character: ranges of characters given by cons cell with car being the first character of the range and cdr being the last character. This helps when you have many characters which have to invoke the same handler. It also accepts nil meaning "all characters in the table".

For more info, such as functions which inspect the table and iterate over its contents see: https://www.gnu.org/software/emacs/manual/html_node/elisp/Char_002dTables.html#Char_002dTables

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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