如何在Emacs中切换区域内的字母大小写

8
我该如何在Emacs中切换区域文本的字母大小写(将大写字母转换为小写,将小写字母转换为大写)?
有列出转换命令,但没有切换命令。
示例:
PLease toggLE MY LETTER case 应变成: plEASE TOGGle my letter CASE

1
看起来有几个尝试回答的答案没有看到您实际所要求的用例,因此它们解决了不同的问题。您能否解释一下这在哪些情况下会有用,即使只是为了我们的娱乐? - tripleee
1
这可能不太常见,但我因为错误地切换了语法文件中的终端和非终端而想到是否有一个命令可以将它们反转。在标记和值等类似情况下也可能会发生这种情况。现在我在思考,如果有这样一个命令,它可以用于大写和小写两种情况。 - Basel Shishani
5个回答

6
您可以使用正则表达式替换来完成此操作:
M-x replace-regexp RET
\([[:upper:]]+\)?\([[:lower:]]+\)? RET
\,(concat (downcase (or \1 "")) (upcase (or \2 ""))) RET

你可以自行绑定一个按键来执行这个操作。


替换中有一个额外的括号,但这个是获奖者。 - Miserable Variable
1
是的,我在你发表评论前不久注意到并进行了修正。 - angus

3

命令upcase-regiondowncase-regioncapitalize-region不是切换命令,它们可能是您所提到的“转换”命令。以下是一个在它们之间循环的命令。

 (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)))

3
我为您编写了这段代码,虽然没有经过充分测试,但看起来可以满足您的需求。
它的逻辑是循环遍历文本中的每个字符。如果字符与小写字符相等,则将其附加到返回字符串中的大写形式。否则,将其附加为小写形式。最后,删除区域并插入返回字符串。
它可以立即在文本页面上运行,但我建议不要在大文本上使用它(仍应该可以正常工作)。
(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))))

1
如果您想改变字母大小写,那么这个函数可以很好地实现: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")) )
    ) )

将区域中的每个字母从大写转换为小写,从小写转换为大写。 - Basel Shishani

0

我喜欢另一个答案比较this-commandlast-command的技巧,所以我已经将它融入到我的旧函数中。这是结果:

(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)

无法测试您的代码:符号的函数定义为空:char-upcasep。 - Basel Shishani

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接