1

I am writing a function to do replacements on a highlighted region. It appears that while region-end changes after each replace, the value is not correct. That is, it does not point to the last character of the initial highlighted region. I am using CUA. Here is a shortened version of my function.

(defun sql-cln ()
  (interactive)
  (progn
    (replace-string "\"" ""  nil (region-beginning) (region-end))
    (replace-string "\t" ""  nil (region-beginning) (region-end))
    (replace-string "\n" ""  nil (region-beginning) (region-end))
    (replace-regexp " +" " " nil (region-beginning) (region-end))
))

Here's the text I test it on.

   select x.group_id, g.loc_prefix"
            "  from station_group_xref x, station_group g"
            " where x.station_id = $1"
                "   and g.loc_grp = 1"
                "   and x.group_id = g.group_id

1 Answer 1

3

The problem is that you're using replace-string and replace-regexp. As the help string warns you, these functions are not meant to be used in a Lisp program. Instead you should run a loop around a search function and replace-match.

The specific difficulty you're facing is that these functions change the point and mark. They set the mark to the beginning of the region that is processed and the point ends up at the end of the last replacement, or at the beginning of the region if there is no replacement.

Setting a variable to the value of (region-end) would not work because these return integers, and the position of the end of the region changes as you make changes inside the region. If you want to make multiple passes, you need a marker. Alternatively, to work on a particular section of the buffer, narrow it to that section.

You can do the replacement in a single pass: search for the disjunction of all the possibilities, and replace accordingly.

(defun sql-cln (beg end)
  (interactive "r")
  (save-restriction
    (narrow-to-region beg end)
    (goto-char (point-min))
    (while (re-search-forward "[\t\n\"]+\\|  +" nil t)
      (replace-match (if (eq (char-after (1- (point))) ?\ ) " " "")))))

or

(defun sql-cln (beg end-pos)
  (interactive "r")
  (let ((end-marker (make-marker))))
    (set-marker end-marker end-pos)
    (goto-char beg)
    (while (re-search-forward "[\t\n\"]+\\|  +" end-marker t)
      (replace-match (if (eq (char-after (1- (point))) ?\ ) " " "")))))
1
  • Thanks. Very informative. A lot of information I need to digest.
    – David
    May 3, 2017 at 13:48

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.