Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Say I have the following

DRAFT,
SAVED,
ARCHIVED,
DELETED;

And I want the following:

DRAFT("draft"),
SAVED("saved"),
ARCHIVED("archived"),
DELETED("deleted");

How can I do this with vim? I'm guessing that I can use visual block mode?

I realize I could easily do this with sed, but I'm interested in any way that I could do this WITHOUT leaving vim.

share|improve this question
    
Well, sed and Vim use very similar regular expressions so… what would you do in sed? –  romainl May 10 '13 at 21:03

4 Answers 4

up vote 3 down vote accepted
:%s/\v(\w*)([,;])/\1("\L\1")\2

seems to do what you ask.

  • \v reduces the number of backslashes
  • (\w*) first group, any number of "word" characters
  • ([,;]) second group, , or ;
  • \1 reuse the first group
  • ("\L\1") lowercased first group between quotes and parentheses
  • \2 second group
share|improve this answer
:1,$s/\<\(\w*\)\>/\1("\L\1")/

This finds a word \<(w*\)\> then puts it as is \1 and lower case \L\1

share|improve this answer
    
This did not seem to work. It seems to not be able to match the words. Probably because they start with whitespace. I should have mentioned that. Instead, the command prepended ("") to the beginning of each line and did not remove the actual words. –  Charlotte May 10 '13 at 20:48
    
If I modify it slightly to add whitespace chars, it gets closer but not quite. :16,20s/\s*[A-Z]*/&("\L&")/ How can I modify this so that the whitespace is ignored when we go to insert the word within the parenthesis? –  Charlotte May 10 '13 at 20:53
    
Use [^,;] instead of [A-Z] on my original command –  parkydr May 10 '13 at 20:55
    
Use s/ *\([A-Z]*\)/\1("\L\1")/ instead to ignore leading whitespace. Or leading anything. The \( \) create a numbered capture group--\1 in this case. –  jpaugh May 10 '13 at 20:57
    
Try my updated answer –  parkydr May 10 '13 at 21:09

For people who prefere ruby:

:rubydo x = $_[0..-2] ; $_ = "#{x}(\"#{x.downcase}\")#{$_[-1]}"

x = $_[0..-2] -> don't save the last char (, or ;)

$_[-1] -> "," or ";"

share|improve this answer

I'd do this with a macro, myself. Assuming that the cursor is at the start of the first line:

qqyeea("<C-R>0")<ESC>v%gu+q3@a

It's far less typing this way, and doesn't require you to remember vim's regex syntax. Often it can turn out to be much quicker to do this sort of text conversion using a macro than by using a substitute command.

Breaking down my solution:

  • qa starts recording a macro into register 'a'.
  • ye yanks from the cursor's current position to the end of the word, storing it into both the " and the 0 register. (I'll only access it via the 0 register, but it actually gets stored in both)
  • e moves the cursor to the end of the word
  • a enters insert mode AFTER the cursor (so between the word and the comma)
  • Next I enter some standard text. The interesting bit is the <C-R>0. In insert mode, <C-R>n means "insert the text that's in the register n". If I was doing this task normally (rather than explaining it to someone else in text form), I'd actually use <C-R>" here, but the 0 is easier to visually distinguish from the literal " characters surrounding it.
  • <ESC> returns us to normal mode. The cursor is now on the closing ) which was the last character we typed in insert mode.
  • v enters visual mode.
  • % jumps the cursor back to the open parenthesis matching the close parenthesis we're currently on, so our visual selection now covers the string ("DRAFT").
  • gu converts the visually selected string to lowercase. This has no effect on the parentheses or quotes within the visual selection.
  • + advances the cursor to the start of the next line, ready to run the same set of commands again.
  • q finishes recording the macro.
  • 3@a runs our macro 'a' three times, thus repeating everything we did on the first line on the three subsequent lines.
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.