7

How can I toggle the case of letters (switch uppercase letters to lowercase and lowercase letters to uppercase) of a region's text in Emacs?

There are listed commands for conversion but nothing for toggling.

Example:

PLease toggLE MY LETTER case

should become:

plEASE TOGGle my letter CASE

4

5 回答 5

7

You can do it with a regexp substitution:

M-x replace-regexp RET
\([[:upper:]]+\)?\([[:lower:]]+\)? RET
\,(concat (downcase (or \1 "")) (upcase (or \2 ""))) RET

It's up to you to bind a key to this.

于 2013-08-16T16:40:31.870 回答
3

I wrote it for you; it did not have thorough testing, but it appears to do what you seek.

The logic behind it is to loop over every single character in the text. If the character is equal to the character in downcase, append it to the return string in upcase. If not, append it in downcase. At the end, delete region and insert the return string.

It works immediate on a page of text, though I'd be wary to use it on huge texts (should be fine still).

(defun toggle-case ()
  (interactive)
  (when (region-active-p)
    (let ((i 0)
      (return-string "")
      (input (buffer-substring-no-properties (region-beginning) (region-end))))
      (while (< i (- (region-end) (region-beginning)))
    (let ((current-char (substring input i (+ i 1))))
      (if (string= (substring input i (+ i 1)) (downcase (substring input i (+ i 1))))
          (setq return-string
            (concat return-string (upcase (substring input i (+ i 1)))))
        (setq return-string
          (concat return-string (downcase (substring input i (+ i 1)))))))
    (setq i (+ i 1)))
      (delete-region (region-beginning) (region-end))
      (insert return-string))))
于 2013-08-16T08:37:07.410 回答
2

Commands upcase-region, downcase-region, andcapitalize-region are not toggles, and are perhaps the "conversion" commands you referred to. Here is a command that cycles among them.

 (defvar cycle-region-capitalization-last 'upper)
 (defun cycle-region-capitalization (&optional msgp)
  "Cycle the region text among uppercase, lowercase and capitalized (title case)."
  (interactive "p")
  (setq cycle-region-capitalization-last
        (case cycle-region-capitalization-last
          (upper  (call-interactively #'downcase-region)   'lower)
          (lower  (call-interactively #'capitalize-region) 'title)
          (title  (call-interactively #'upcase-region)     'upper)))
  (when msgp (message "Region is now %scase" cycle-region-capitalization-last)))
于 2013-08-15T17:15:52.553 回答
1

If you mean letter case, then this function works nicely: http://ergoemacs.org/emacs/modernization_upcase-word.html

(defun toggle-letter-case ()
   "Toggle the letter case of current word or text selection.
   Toggles between: “all lower”, “Init Caps”, “ALL CAPS”."
   (interactive)
   (let (p1 p2 (deactivate-mark nil) (case-fold-search nil))
    (if (region-active-p)
        (setq p1 (region-beginning) p2 (region-end))
      (let ((bds (bounds-of-thing-at-point 'word) ) )
        (setq p1 (car bds) p2 (cdr bds)) ) )
    (when (not (eq last-command this-command))
      (save-excursion
        (goto-char p1)
        (cond
         ((looking-at "[[:lower:]][[:lower:]]") (put this-command 'state "all lower"))
         ((looking-at "[[:upper:]][[:upper:]]") (put this-command 'state "all caps") )
         ((looking-at "[[:upper:]][[:lower:]]") (put this-command 'state "init caps") )
         ((looking-at "[[:lower:]]") (put this-command 'state "all lower"))
         ((looking-at "[[:upper:]]") (put this-command 'state "all caps") )
         (t (put this-command 'state "all lower") ) ) ) )
    (cond
     ((string= "all lower" (get this-command 'state))
      (upcase-initials-region p1 p2) (put this-command 'state "init caps"))
     ((string= "init caps" (get this-command 'state))
      (upcase-region p1 p2) (put this-command 'state "all caps"))
     ((string= "all caps" (get this-command 'state))
      (downcase-region p1 p2) (put this-command 'state "all lower")) )
    ) )
于 2013-08-15T17:10:41.920 回答
0

I liked the other answer's technique of comparing this-command and last-command, so I've incorporated it into my old function. Here's the result:

(defun upcase-word-toggle ()
  (interactive)
  (let ((bounds (bounds-of-thing-at-point 'symbol))
        beg end
        regionp)
    (if (eq this-command last-command)
        (setq regionp (get this-command 'regionp))
      (put this-command 'regionp nil))
    (cond 
      ((or (region-active-p) regionp)
       (setq beg (region-beginning)
             end (region-end))
       (put this-command 'regionp t))
      (bounds 
       (setq beg (car bounds)
             end (cdr bounds)))
      (t 
       (setq beg (point)
             end (1+ beg))))
    (save-excursion
      (goto-char (1- beg))
      (and (re-search-forward "[A-Za-z]" end t)
           (funcall (if (char-upcasep (char-after)) 
                        'downcase-region 
                      'upcase-region)
                    beg end)))))

(defun char-upcasep (letter)
  (eq letter (upcase letter)))

(global-set-key (kbd "C->") 'upcase-word-toggle)
于 2013-08-15T17:40:33.247 回答