41

If for some reason I want to selectively convert camelCase named things to being underscore separated in vim, how could I go about doing so?

Currently I've found that I can do a search /s[a-z][A-Z] and record a macro to add an underscore and convert to lower case, but I'm curious as to if I can do it with something like :

%s/([a-z])([A-Z])/\1\u\2/gc

Thanks in advance!

EDIT: I figured out the answer for camelCase (which is what I really needed), but can someone else answer how to change CamelCase to camel_case?

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Jeff
  • 1,807
  • 1
  • 15
  • 17

7 Answers7

66

You might want to try out the Abolish plugin by Tim Pope. It provides a few shortcuts to coerce from one style to another. For example, starting with:

MixedCase

Typing crc [mnemonic: CoeRce to Camelcase] would give you:

mixedCase

Typing crs [mnemonic: CoeRce to Snake_case] would give you:

mixed_case

And typing crm [mnemonic: CoeRce to MixedCase] would take you back to:

MixedCase

If you also install repeat.vim, then you can repeat the coercion commands by pressing the dot key.

nelstrom
  • 18,802
  • 13
  • 54
  • 70
  • 4
    I think this is the best answer. No need to reinvent the wheel. – Kelvin May 17 '12 at 16:57
  • Really nice plugin, it also covers systematically replacing multiple variants of words with single command e.g. child -> adult and children -> adults – RichVel Oct 29 '19 at 10:27
  • Remedial question, I can't seem to figure out how to "type crc". I've tried being in normal, visual, insert, and select modes. – Dave Aaron Smith May 13 '20 at 16:41
  • Oh, but maybe I installed it wrong? The installation instructions say "Extract in ~/.vim or ~\vimfiles" so I extracted abolish.zip into ~/.vim but as far as I can tell I haven't actually accomplished anything. – Dave Aaron Smith May 13 '20 at 16:44
39

This is a bit long, but seems to do the job:

:%s/\<\u\|\l\u/\= join(split(tolower(submatch(0)), '\zs'), '_')/gc

Raimondi
  • 5,163
  • 31
  • 39
  • 3
    In order to not match words that start with uppercase, I modified this regex slightly: `%s/\( \)\@<!\<\u\|\l\u/\=len(submatch(0)) == 1 ? tolower(submatch(0)) : submatch(0)[0].'_'.tolower(submatch(0)[1])/gc` – Mert Nuhoglu Mar 01 '18 at 10:46
  • 1
    The first branch of the answer's regex (`\<\u`) matches the upper case letter in `Word`, so if you don't want to match them, just remove `\<\u\|` and use `\l\u`as the regex: `:%s/\l\u/...` – Raimondi Apr 01 '18 at 21:01
  • @MertNuhoglu is there a way to let it walk back if people miss skip one match? Thanks! – roachsinai Aug 19 '21 at 13:38
  • Fantastic answer thanks, although for PascalCase, not camelCase. As Raimondi says, `%s/\l\u/\= join(split(tolower(submatch(0)), '\zs'), '_')/g` replaces camelCase only, and I also removed the final `c` so that it won't prompt me for confirmation of each match several hundred times – theonlygusti Jan 17 '22 at 00:26
17

I suppose I should have just kept trying for about 5 more minutes. Well... if anyone is curious:

%s/\(\l\)\(\u\)/\1\_\l\2/gc does the trick.

Actually, I realized this works for camelCase, but not CamelCase, which could also be useful for someone.

Jeff
  • 1,807
  • 1
  • 15
  • 17
7

I whipped up a plugin that does this. https://github.com/chiedojohn/vim-case-convert

To convert the case, select a block of text in visual mode and the enter one of the following (Self explanatory) :

:CamelToHyphen :CamelToSnake :HyphenToCamel :HyphenToSnake :SnakeToCamel :SnakeToHyphen

To convert all occerences in your document then run one of the following commands:

:CamelToHyphenAll :CamelToSnakeAll :HyphenToCamelAll :HyphenToSnakeAll :SnakeToCamelAll :SnakeToHyphen

Add a bang (eg. :CamelToHyphen!) to any of the above command to bypass the prompts before each conversion. You may not want to do that though as the plugin wouldn't know the different between variables or other text in your file.

Chiedo
  • 7,288
  • 3
  • 26
  • 22
2

For the CamelCase case:

%s#(\<\u\|\l)(\l+)(\u)#\l\1\2_\l\3#gc

Tip: the regex delimiters can be altered as in my example to make it (somewhat) more legible.

michaelmichael
  • 13,755
  • 7
  • 54
  • 60
1

For the camelCase:

%s/\v<([a-z_]+)([A-Z][a-zA-Z]+)>/\1_\l\2/gc

You may need to run this command multi times.

Ela Dute
  • 686
  • 8
  • 13
0

I have an API for various development oriented processing. Among other things, it provides a few functions for transforming names between (configurable) conventions (variable <-> attribute <-> getter <-> setter <-> constant <-> parameter <-> ...) and styles (camelcase (low/high) <-> underscores). These conversion functions have been wrapped into a plugin.

The plugin + API can be fetch from here: https://github.com/LucHermitte/lh-dev, for this names conversion task, it requires lh-vim-lib

It can be used the following way:

  • put the cursor on the symbol you want to rename
  • type :NameConvert + the type of conversion you wish (here : underscore). NB: this command supports auto-completion.
  • et voilà!
Luc Hermitte
  • 31,979
  • 7
  • 69
  • 83