34

Is there an emacs function to convert a camel-cased word to underscore? Something, like:

longVariableName

M-x to-underscore

long_variable_name

Zach Young
  • 10,137
  • 4
  • 32
  • 53
David Nehme
  • 21,379
  • 8
  • 78
  • 117
  • 2
    You might also be interested in `M-x glasses-mode` which magically inserts underscores in the buffer without modifying the underlying file. – Ben Feb 16 '12 at 00:00

7 Answers7

45

Use the string-inflection package, available on MELPA, or at https://github.com/akicho8/string-inflection.

Useful keyboard shortcuts, copied from https://www.emacswiki.org/emacs/CamelCase :

;; Cycle between snake case, camel case, etc.
(require 'string-inflection)
(global-set-key (kbd "C-c i") 'string-inflection-cycle)
(global-set-key (kbd "C-c C") 'string-inflection-camelcase)        ;; Force to CamelCase
(global-set-key (kbd "C-c L") 'string-inflection-lower-camelcase)  ;; Force to lowerCamelCase
(global-set-key (kbd "C-c J") 'string-inflection-java-style-cycle) ;; Cycle through Java styles
Evgeniy Berezovsky
  • 18,571
  • 13
  • 82
  • 156
Nik
  • 2,380
  • 2
  • 16
  • 15
25

I use the following for toggling between camelcase and underscores:

(defun toggle-camelcase-underscores ()
  "Toggle between camelcase and underscore notation for the symbol at point."
  (interactive)
  (save-excursion
    (let* ((bounds (bounds-of-thing-at-point 'symbol))
           (start (car bounds))
           (end (cdr bounds))
           (currently-using-underscores-p (progn (goto-char start)
                                                 (re-search-forward "_" end t))))
      (if currently-using-underscores-p
          (progn
            (upcase-initials-region start end)
            (replace-string "_" "" nil start end)
            (downcase-region start (1+ start)))
        (replace-regexp "\\([A-Z]\\)" "_\\1" nil (1+ start) end)
        (downcase-region start (cdr (bounds-of-thing-at-point 'symbol)))))))
ens
  • 1,068
  • 13
  • 14
21
(progn (replace-regexp "\\([A-Z]\\)" "_\\1" nil (region-beginning) (region-end))
       (downcase-region (region-beginning) (region-end)))
sigjuice
  • 28,661
  • 12
  • 68
  • 93
mathk
  • 7,973
  • 6
  • 45
  • 74
  • 5
    To assign `to-underscore` (so you can do `M-x to-underscore`): `(defun to-underscore () (interactive) (progn (replace-regexp "\\([A-Z]\\)" "_\\1" nil (region-beginning) (region-end)) (downcase-region (region-beginning) (region-end))) )` – Lucian Adrian Grijincu Mar 30 '17 at 19:35
10

I use this when converting C# code to PHP.

(defun un-camelcase-word-at-point ()
  "un-camelcase the word at point, replacing uppercase chars with
the lowercase version preceded by an underscore.

The first char, if capitalized (eg, PascalCase) is just
downcased, no preceding underscore.
"
  (interactive)
  (save-excursion
    (let ((bounds (bounds-of-thing-at-point 'word)))
      (replace-regexp "\\([A-Z]\\)" "_\\1" nil
                      (1+ (car bounds)) (cdr bounds))
      (downcase-region (car bounds) (cdr bounds)))))

And then in my php-mode fn:

(local-set-key "\M-\C-C"  'un-camelcase-word-at-point)
Cheeso
  • 189,189
  • 101
  • 473
  • 713
7

There is now another general way in 2018: magnars/s.el: The long lost Emacs string manipulation library. - github.com, some examples regarding OP's question:

  1. whatever case to snake case(underscore seperated):

    (s-snake-case "some words") ;; => "some_words"
    (s-snake-case "dashed-words") ;; => "dashed_words"
    (s-snake-case "camelCasedWords") ;; => "camel_cased_words"
    
  2. whatever case to lower camel case:

    (s-lower-camel-case "some words") ;; => "someWords"
    (s-lower-camel-case "dashed-words") ;; => "dashedWords"
    (s-lower-camel-case "under_scored_words") ;; => "underScoredWords"
    

see more examples at its repo.

whatacold
  • 660
  • 7
  • 15
1

If you want to get complete code using s.el:

(defun to-snake-case (start end)
  "Change selected text to snake case format"
  (interactive "r")
  (if (use-region-p)
      (let ((camel-case-str (buffer-substring start end)))
        (delete-region start end)
        (insert (s-snake-case camel-case-str)))
    (message "No region selected")))
azzamsa
  • 1,805
  • 2
  • 20
  • 28
0

@ens' answer was close, but a little buggy for me on Emacs 26.1. I fixed the bug and added the ability, via C-u prefix arg, to specify if you want the first letter of camel case to be lower case:

(defun toggle-camelcase-underscores (first-lower-p)
  "Toggle between camelcase and underscore notation for the
symbol at point. If prefix arg, C-u, is supplied, then make first
letter of camelcase lowercase."
  (interactive "P")
  (save-excursion
    (let* ((bounds (bounds-of-thing-at-point 'symbol))
           (start (car bounds))
           (end (cdr bounds))
           (currently-using-underscores-p (progn (goto-char start)
                                                 (re-search-forward "_" end t))))
      (if currently-using-underscores-p
          (progn
            (replace-string "_" " " nil start end)
            (upcase-initials-region start end)
            (replace-string " " "" nil start end)
            (when first-lower-p
              (downcase-region start (1+ start))))
        (replace-regexp "\\([A-Z]\\)" "_\\1" nil (1+ start) end)
        (downcase-region start (cdr (bounds-of-thing-at-point 'symbol)))))))
Joe
  • 965
  • 11
  • 16