Vim Tutorial: Swapping Columns

Many unix text files are formatted into columns (database files come to mind). Sometimes, it is useful to be able to change the order of the columns.

To change the columns, we need to know what the column separator is, and how it is treated if it (that is, its literal character) occurs within the column. For this example assume the separator is a tab, and for simplicity assume that the tab does not appear at all within the columns.

We commence by typing a colon to initiate a command, next we give the range of lines over which the command is to run. In this case, we want to swap the columns on all lines in the file. The percent sign is an abbreviation for ‘all lines in the file’. Next we enter the command to perform on each line, which in this case is ‘s’, an abbreviation for the ‘substitute’ command. We then give the pattern to search for, and the string to replace it with, between slash characters.

In contrast to most simple search–and–replace operations, we wish to retain the searched–for string and use it in the replaced string. This is because we want to match one or more columns, and then replace them in a different order. We achieve this effect using the string “\(” to begin the part of the search string to retain and “\)” to end it.

We then tell Vim where in the replace string to include these retained parts by entering a slash followed by a digit at the place in the replace string where the restored string is to go. In the replace expression, an ampersand symbol (&), and the string \0, insert the entire searched–for string. A backslash followed by a digit inserts the part of the searched–for string contained between the corresponding \( ... \) pair (e.g. \1 inserts the matched string contained within the first pair).

Thus, to change “Neil Carter” to “Carter, Neil” (ignoring the quotes), the search string would be:

\(Neil\) \(Carter\)

(Note that the space between the names need not be quoted in the search pattern.)

And the corresponding replace string would be:

\2, \1

A rule–of–thumb regular expression for a delimiter–separated column consists merely of an exclusive set that contains only the delimiter character. Beware: this only works if the delimiter character does not appear literally within the column. For instance, a colon–delimited column can be defined with the regular expression [^:]+, which actually means “one or more characters that are not the delimiter character”, or more simply, “all the characters from here until the delimiter character”.

In Vim, nonprintable or control characters are entered by pressing CTRL&V followed by the CTRL key combination for the required character. The CTRL key combination for tab is CTRL&I, so to enter a tab character in the search and replace strings, press CTRL&V followed by CTRL&I. For a tab-–delimited column then, we have:

[^^I]\+^I

which means one or more non–characters, plus the tab at the end of this column. We keep the tab at the end so that when we reinsert the column, it will still have something to separate it from the next column.

You may have to exercise some care in deciding whether to group the column together with the separator to the left, or the separator to the right. You will need to consider where the column is, prior to, and subsequent to, the substitute operation; if you are searching for the first column, there is no tab before it. Similarly, if you are moving the first column to the end of the line, it won't make much sense to append the tab since there will be no following column to separate it from. You will also need to consider the placement of the separator when moving the last column to the beginning of the line. You may also need to consider the case of empty columns (my example requires a column containing at least one character).

Putting all this together, we have the following commmand, which swaps the first and second columns. The initial caret symbol (^) is there to ensure that the initial column string matches only the first column of each line. The c at the end tells Vim to ask us to confirm that we wish to make each replacement. This is very handy for checking that the command is correct.

%s/^\([^^I]\+^I\)\([^^I]\+^I\)/\2\1/c

Note that the + symbol (meaning one or more occurrences) has to be ‘escaped’ in Vim, in contrast to conventional regular expression syntax. Which characters have to be escaped is dictated by the magic option in Vim, which is on by default. For more information on this and the Vim features used in this tutorial, issue the following commands in Vim:


Home About Me
Copyright © Neil Carter

Content last updated: 2004-05-19