Back-references in Neovim Substitution

In the searching we learned how to search for text in a buffer. Later, we learned how to expand our search capabilities with patterns in order to more precisely target the words and patterns we wanted to search for.

In this chapter we learn how to extend this capability even further, with replacements.

Lets start with the same buffer we used in the previous example:

Initial Conditions
Madison·Angelica·Mcbride
Sarah·Kristine·Ryan
Daniel·Justin·Baker
Meagan·Linda·Harvey
Abigail·Julia·Lewis
Megan·Jacqueline·Morris
Preston·Daniel·Moore
Sheryl·Michelle·Hill
COMMAND
Top
1:1
:%s/^\(\w\+\)\s\(\w\)\w\+\s\(\w\+\)$//n

The names in this file are listed in this format:

First Middle Last

but we would like them to be listed like this:

Last, First M

Let's start by building our search pattern. First, we want to search the entire file, so we start with the range and substitution command:

:%s/

Next, a pattern that will capture multiple word characters is:

\(\w\+\)

so, to capture the first name we have:

:%s/^\(\w\+\)\s

where we added the ^ anchor to ensure that we match from the start of the line, and a \s to match the space character between the first and middle names.

Since we want to replace the middle name with just the middle initial, we need to match the entire middle name, but only capture the first letter. This can be done with the following sub-pattern:

\(\w\)\w\+

Finally, we can capture the last name using the same pattern we used for the first name. Putting that all together we get the following search pattern:

:%s/^\(\w\+\)\s\(\w\)\w\+\s\(\w\+\)$

where we included the space between the middle and last names, and added the $ anchor to make sure that the pattern matches all the way to the end of the line.

Let's test this pattern by executing with the n flag:

:%s/^\(\w\+\)\s\(\w\)\w\+\s\(\w\+\)$//n
Check the search pattern
Madison·Angelica·Mcbride
Sarah·Kristine·Ryan
Daniel·Justin·Baker
Meagan·Linda·Harvey
Abigail·Julia·Lewis
Megan·Jacqueline·Morris
Preston·Daniel·Moore
Sheryl·Michelle·Hill
NORMAL
Top
1:1
8 matches on 8 lines

OK, looks good. Now, lets build our replacement string.

Our search pattern had 3 capturing groups, one for each of the first, middle, and last names. Starting from the left and counting groups, the group references are:

  1. First name
  2. Middle initial
  3. Last name

We can arrange the name in the desired format with the following replacement string:

\3, \1 \2

So our final substitution command is:

:%s/^\(\w\+\)\s\(\w\)\w\+\s\(\w\+\)$/\3, \1 \2/

Now, lets execute the substitution and check the result:

Execute the subsitution
Mcbride,·Madison·A
Ryan,·Sarah·K
Baker,·Daniel·J
Harvey,·Meagan·L
Lewis,·Abigail·J
Morris,·Megan·J
Moore,·Preston·D
Hill,·Sheryl·M
NORMAL
89%
8:1
8 substitutions on 8 lines

Which was the result we were looking for.

Replacement string support a few formatting options, which provide control over the case that replacement content is displayed in:

Format Description
\u Make the next character upper-case
\U Make the following characters upper-case, until \e
\l Make the next character lower-case
\L Make the following characters lower-case, until \e
\e Make the end of case sequence, started with \u, \U, \l and \L
\E Same as \e

There are also a few escaping options that can be included in the replacement string:

Escape Description
\ Insert a single back-slash
\t Insert a tab
\n Insert a new-line character

As a quick demo of how to use these options, suppose we wanted to display the middle-initial in lower-case, and separate the first name from the last name by a tab character. This can be achieved by modifying the replacement string as follows:

:%s/^\(\w\+\)\s\(\w\)\w\+\s\(\w\+\)$/\3,\t\1 \l\2/

which, when executed, produces the result:

Execute the subsitution with formatting
Mcbride,⇥Madison·a
Ryan,⇥Sarah·k
Baker,⇥Daniel·j
Harvey,⇥Meagan·l
Lewis,⇥Abigail·j
Morris,⇥Megan·j
Moore,⇥Preston·d
Hill,⇥Sheryl·m
NORMAL
89%
8:1
8 substitutions on 8 lines