Solutions to Exercises

Solution 4.1 — Substituting the second-to-last element on a line

When there are two or more wild cards in a search pattern, Vim finds the longest match for the first one that allows any match for the subsequent ones, and so on.

  % substitute /\(.*\)k37\(.*k37\)/\1q53\2

Solution 4.2 — Setting a line to Title Case

Because the original lines could be any mix of case, we have to capture and operate on each word. Because we want the first letter to be upper-case and the rest of the letters in the word to be lower-case, we capture them separately and operate on them in the replacement part as \1 and \2 respectively. Recall that \u operates on the following letter whereas \L operates on the following word.

  237 , 289 substitute /\(\w\)\(\w\+\)/\u\1\L\2/g

If you’re just changing an all lowercase line into Title Case, the substitution is much simpler:

 237 , 289 substitute /\<\w/\u&/g

So, an alternative way to Title Case a line without using explicit capture:

  237 , 289 global /./ substitute /.*/\L&/ | s/\<\w/\u&/g

Solution 4.3 — Substituting the third element in a line of many

  1. Deleting The Third Column

    We use \zs to focus the match within the search part of a substitution while using the patterns outside of these markers as anchors. Assuming you’ve visually selected the lines you want to operate on, the following substitute will delete column 3 from all rows:

      '< , '> substitute /\(\d\+,\s*\)\{2}\zs\d\+,\s*//
    

    The {2} notation is Vim’s way of requiring two repetitions of the previous element, which in this case is a number followed by a comma — effectively stepping past the first two columns. We then start our match with \zs, restricting it to only the third column.

  2. Doubling The Numbers In The Third Column

    Note

    Read the Substitute With An Expression section if you don’t know how to approach this problem.

    Much the same approach is taken in the search side of the substitute to narrow our search down to just column three — however because this time we want to double the numbers and not delete the whole column, we’re narrowing down even more to just the numbers themselves. The replacement needs to be an expression so we enter expression mode by starting the replacement string with the \= special. Within a replacement expression, we use submatch(1) to refer to the first captured text in the match (what \1 would ordinarily give us, but which can’t be used inside an expression replacement.)

      '< , '> substitute /\%(\d\+,\s*\)\{2}\zs\d\+/\=submatch(0)*2/
    

    We use the non-capturing \%(…\) group in the column skip section to make the replacement clearer — submatch(0) now refers to column three which starts after the \zs marker. Non-capturing groups are slightly more efficient, but I usually use them to reduce confusion, as shown in this example.

Solution 4.4 — A Seemingly Useless Substitution

So, what does this seemingly useless substitute do?

  % substitute /^$

It counts the number of blank lines in your file. That might still sound useless to you, unless you always separate your paragraphs with a single blank line. Now you know how many paragraphs you’ve written!

Solution 4.5 — Avoiding Duplicating HTML Paragraph Tags

  1. Using Multiple Simple Substitutions (Bottom-Up Approach)

    Where the substitution command to add a tag at the start of a paragraph presently removes and then replaces any first character on the line, now it should remove and replace anything except a “<” character in that position. If that first character is a “<” it is necessary that the substitution command fail so it will change nothing. To arrange this, replace that period in the search pattern with a negative character class — [^<] — which matches any character except the one that begins every HTML tag. Similarly, replace the period in the other substitution pattern with the negative character class that matches any character except the one that always ends an HTML tag. Now the two commands will look like this:

      global /^$/ + substitute /^[^<]/<p>&/
      global /^$/ - substitute :[^>]$:&</p>:
    

  2. Using A Single Complex Substitution

    Perhaps now you’ll appreciate the simplicity of using bottom-up techniques to break complex edits down into multiple simpler substitutions.

      % substitute /.\(<.\+>\)\@<!\zs\n\n\+\ze\(<.\+>\)\@!/<\/p>&<p>/