6

I have a series of single-word codes on separate lines in a text file. I'd like to add a backquote ( ` ) to the beginning and end of each word.

I know I can add a backquote to the beginning of each line with relative ease: Ctrl-v --> Shift-I. How do I insert text after the first word on each line?

  • Welcome to Vi and Vim! – filbranden Jul 9 at 3:55
  • Are the words the only thing on each line? You can also use Shift-A with visual block mode. – Rich Jul 9 at 7:04
  • @Rich Specifically not--otherwise I would just add the backquote to the end of each line as well as the beginning. – Yehuda Jul 9 at 12:14
8

You can also use

:%s/\w\+/`&`

to convert from

Lorem
ipsum
dolor
sit
amet

to

`Lorem`
`ipsum`
`dolor`
`sit`
`amet`
  • :% range to the next command (whole buffer)
  • s is a substitute command :s/regexWhat/substituteValue without range will substitute on a current line.
  • \w\+ is a regexp for a word
  • & is a whole value of what has been matched with regexpWhat, in this example a word
| improve this answer | |
  • Can you walk me through each of those commands? Does this work by just ending each line with a backtick or specifically ending the first word on each line with a backtick? – Yehuda Jul 9 at 14:26
4

You can use the :normal command, which allows you to run a sequence of Normal mode commands. When given a range, it repeats the sequence for every line. (It also starts at the beginning of each line, when given a range.)

So you could use the e motion (end of the word, for a definition of word that includes keyword characters) or E (going up to the first blank character), followed by a to append and then a ` to insert the character. (You don't need an explicit <Esc> when using :normal, it exits insert mode implicitly at the end of the sequence.)

For the range, assuming you want a subset of lines (for the whole buffer you'd use :%), you could use a visual selection to pick which lines to act on. When you press : from Visual mode, Vim will automatically insert :'<,'>, which is a range for the most recent Visual selection.

So you could then run:

:'<,'>normal Ea`

This almost works flawlessly, but it fails on any blank lines, since on those lines the E (or e) motion will jump to the end of the first word of the next non-blank line, you will end up appending two or more `s to the first word on lines that follow blank lines... To fix that, you could then use a :g command with a /\S/ regex, to only execute the :normal command on lines which match that pattern, in other words, lines with at least one non-blank character.

:'<,'>g/\S/normal Ea`

In some cases, you can simplify the procedure (while still supporting blank lines) by using a motion such as f{char} or t{char}. For example, if words are limited by commas (such as in a CSV file), you can use f, or t, to find the first comma (or even a count to find the nth one.)

The advantage of using that type of movement is that it's guaranteed to only match on the current line. Furthermore, :normal will interrupt the command sequence if one such movement fails. So you can use that sequence without worrying about blank lines or lines without the matching character, since they'll just be silently skipped. No need to use :g to filter those out in that case.

:'<,'>normal f,i`

Note that you can also use this technique using :normal to insert the leading ` to the beginning of lines:

:'<,'>g/\S/normal I`

The advantage of this approach over using a visual block mode is that using :normal with I will insert the text snippet at the first non-blank position in the line (preserving indentation), while visual block insertion is limited to inserting it to a specific fixed column on every line.

| improve this answer | |
2

Filbranden’s answer is what I would go with in my editing; I would type the first command (append), then use q: to edit it into the second (if I didn’t have surround.vim; see bottom).

But there are other options: for example, a macro

qqI`<Esc>ea`<Esc>jq

When repeated with @q (or @@, once replayed once), it will do the backticks for the first word on the current line and move down a line. Using a count will do that many consecutive lines. This one doesn’t handle blank lines, but you could use a similar trick:

[range]global/\S/normal! @q

Another option with the surround.vim plugin:

[range]global/\S/normal ysiw`
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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