Using Vim's Very Magic Regex to Format Code

Do you ever find yourself typing the same string formats in code on repeat? Vim’s regex search and replace is a powerful tool for automating this problem. It doesn’t come up everyday, but frequently enough that I forget the next time I need it. With vim’s regex, we can turn this:

one
two
three

into this:

("ONE", "One"),
("TWO", "Two"),
("THREE", "Three"),

1. Let’s Build A Regex

1.1 Duplicating Words

First we need to duplicate our words by:

  1. pressing :
  2. typing %s/\w\+/\0 \0/
  3. hitting enter

This will result turn our original input into:

one one
two two
three three
  • %s the range of the substitute command, in our case the entire file.
  • \w matches any alphanumeric character or underscore [a-zA-Z0-9_]
  • \+ greedy match preceding character 1 or more times
  • \0 \0 will replace with the previous matching pattern twice with a space between

1.2 Upper/Lower Casing

Alright, now let’s look into setting the casing. We want the first word uppercase, capitalize the first character of the second word, then all lower case. Vim’s \u, \U, and \L will work nicely.

  • \u uppercases the next character.
  • \U uppercases the following characters
  • \l and \L are the same for lowercase

Using our original input, we can update our regex to %s/\w\+/\U\0\L \u\0/:

ONE One
TWO Two
THREE Three

1.3 Special Characters

The last thing we need is to add some (, ", and , to the text. But, ( and , have special meaning in regex. That means we need to escape them by adding a backslash (\( and \, for example) Hold on, the regex is about to get messy: %s/\w\+/\("\U\0\L"\, "\u\0"\)\,/:

("ONE", "One"),
("TWO", "Two"),
("THREE", "Three"),

Success! We have our regex!

2. Making Vim Regex Magical

Remembering that regex never comes easy for me. Fortunately, vim comes with a feature called “very magic” to help. It assumes every character is a special character, meaning you don’t need to add the backslash. You enable this by adding \v into your regex. This simplifies our last regex to: %s/\v(\w+)/("\U\0\L", "\u\0"),/ Which makes parsing a bit easier.

3. Multiple Words

What if we’re not duplicating words? What if we have different values we want to use? For example:

one red
two blue
three green

Vim can handle that too. In the beginning we used \0 to mean the single matched word. You can search for multiple words and use \1 and \2 to refer to them. If we want to convert to a similar format we could run %s/\v(\w+) (\w+)/("\1", "\2"),/:

("0", "red"),
("1", "green"),
("2", "blue"),

4. Piping To Vim

Don’t quote me on the practical value of this, but it’s fun to know. You can use vim’s regex to replace text in bash pipes.

$ echo "one\ntwo\nthree" | vim -es '+%s/\v(\w+)/("\U\0\L = "\u\0"),/' '+%print' '+:q!' /dev/stdin

("ONE = "One"),
("TWO = "Two"),
("THREE = "Three"),

I’d probably use sed before reaching for vim.

5. Conclusion

Vim’s regex search and replace is a powerful tool in your belt. You can make yaml options %s/\v(\w+)/\0: \0/:

one: one
two: two
three: three

Python dict entries %s/\v(\w+)/"\0": "\0",/:

"one": "one",
"two": "two",
"three": "three",

Or any other format you can think of. It’s language agnostic and useful in all kinds of situations. Happy Regexing!