1

This is a very rudimentary question, but I have a document in which I need to replace many different words fairly frequently, so I created a function that goes like this:

(defun chikan ()
  (interactive)
  (goto-line 1)
  (replace-string "ichi" "one")
  (goto-line 1)
  (replace-string "ni" "two")
)

The actual function is a lot longer (the words in the example are just placeholders). I figured out that I had to stick the (goto-line 1) before every (replace-string) because it was going through the whole doc on the first sweep and then stopping, and not replacing words later in the list.

My rudimentary question: is there another way to make it search and replace all words in a document?

3
  • I have written up an answer that uses a different approach, but wanted to mention that the widely accepted approach to programmatically go to the beginning of the buffer is with (goto-char (point-min)) and the end of the buffer is with (goto-char (point-max)).
    – lawlist
    Commented Jan 4, 2021 at 7:09
  • Thanks! I don’t know if I should ask here or elsewhere, but is there an easy way to pass a dictionary (like in Python) to this function, which it could just loop through, substituting variables with the dictionary members?
    – Al Gorithm
    Commented Jan 4, 2021 at 13:55
  • I updated the answer to include an alist, which is similar to a Python data structure. A handful of forum participants have posted hybrid Python / Lisp solutions to a variety of issues ranging from reading email to calendar management, but those types of answers will only help a finite number of future Google / forum searchers looking for solutions to similar issues.
    – lawlist
    Commented Jan 4, 2021 at 14:52

1 Answer 1

1

How about using replace-regexp, which contains optional arguments for START and END? To control lazy highlighting while the search is being performed, the variable query-replace-lazy-highlight can be customized or let-bound to the desired setting; e.g., nil for no lazy highlighting. See also the variables lazy-highlight-initial-delay and lazy-highlight-interval.

(defun chikan ()
"Doc-string."
(interactive)
  (replace-regexp "\\<ichi\\>" "one" nil (point-min) (point-max))
  (replace-regexp "\\<ni\\>" "two" nil (point-min) (point-max)))

The following example uses an alist (similar to the data structure of a Python dictionary), which is an application requested by the O.P. in a follow-up comment underneath the question hereinabove:

(defun chikan ()
"Doc-string."
(interactive)
  (let ((alist '(("ichi" . "one")
                 ("ni" . "two"))))
    (dolist (elt alist)
      (replace-regexp (concat "\\<" (car elt) "\\>")
                      (cdr elt)
                      nil
                      (point-min)
                      (point-max)))))

Rather than using word boundary delimiters in the first argument as depicted in this example, see the optional argument in replace-regexp for DELIMITED which contains a doc-string entry as follows: "Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace only matches surrounded by word boundaries. A negative prefix arg means replace backward."

For an answer that deals with regexp matches that excludes surrounding word constituents, see https://stackoverflow.com/a/5941448/2112489 , the text of which is copied hereinbelow for convenience:

The regexp \<foo\> or \bfoo\b matches foo only when it's not preceded or followed by a word constituent character (syntax code w, usually alphanumerics, so it matches in foo_bar but not in foo1).

Since Emacs 22, the regexp \_<foo_bar\_> matches foo_bar only when it's not preceded or followed by a symbol constituent character. A symbol constituent is either a word constituent or a character with syntax _. Most programming mode define _ to be a symbol constituent.

Your Answer

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

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