Practical Vim< /a> vit Practical Vim< /a> Note that the styling for a Visual selection is the... development I thought I knew Vim, but Practical" name="description"/>
Tải bản đầy đủ - 0 (trang)
Tip 95. Swap Two or More Words

Tip 95. Swap Two or More Words

Tải bản đầy đủ - 0trang

Swap Two or More Words

• 231



The first command replaces the word “dog” with “man,” leaving us with the

phrase “the man bit the man.” Then the second command replaces both

occurrences of “man” with “dog,” giving us “the dog bit the dog.” Clearly, we

have to try harder.

A two-pass solution is no good, so we need a substitute command that works

in a single pass. The easy part is writing a pattern that matches both “dog”

and “man” (think about it). The tricky part is writing an expression that

accepts either of these words and returns the other one. Let’s solve this part

of the puzzle first.

Return the Other Word

We don’t even have to create a function to get the job done. We can do it with

a simple dictionary data structure by creating two key-value pairs. In Vim,

try typing the following:

:let swapper={"dog":"man","man":"dog"}

:echo swapper["dog"]


:echo swapper["man"]


When we pass "dog" as a key to our swapper dictionary, it returns "man", and

vice versa.

Match Both Words

Did you figure out the pattern? Here it is:


This pattern simply matches the whole word “man” or the whole word “dog.”

The parentheses serve to capture the matched text so that we can reference

it in the replacement field.

All Together Now

Let’s put everything together. We’ll start by running the search command.

This should cause all occurrences of “dog” and “man” to be highlighted. Then

when we run the substitute command, we can leave the search field blank

and it will simply reuse the last search pattern (as discussed in Tip 90, on

page 220).

report erratum • discuss

Chapter 14. Substitution

• 232

For the replacement, we’ll have to evaluate a little bit of Vim script. That

means using the \= item in the replacement field. This time, we won’t bother

assigning the dictionary to a variable, we’ll just create it inline for a single


Normally we could refer to captured text using Vim’s \1, \2 (and so on) notation.

But in Vim script, we have to fetch the captured text by calling the submatch()

function (see :h submatch() ).

When we put everything together, this is what we get:




This is a daft example! We have to type out the words “man” and “dog” three

times each. Obviously, it would be quicker to change the two words in the

document, one time each. But if we were working with a large body of text

with multiple occurrences of each word, then this extra effort could quickly

pay for itself. Note that this technique could easily be adapted to swap three

or more words in a single pass.

There still remains the issue of all that typing. With a little bit more Vim

script, we could write a custom command that exposed a more user-friendly

interface that would do all of the repetitive work for us under the hood. That’s

beyond the scope of this book, but check out Abolish.vim: A Supercharged

Substitute Command, on page 232, for inspiration.

Abolish.vim: A Supercharged Substitute Command

One of my favorite plugins from Tim Pope is called Abolish.a It adds a custom command

called :Subvert (or :S for short), which acts like a supercharged version of Vim’s :substitute

command. Using this plugin, we could swap the words “man” and “dog” by issuing

the following command:


Not only is this easier to type, but it’s much more flexible too. As well as replacing

“man” with “dog” (and vice versa), it would also replace “MAN” with “DOG” and “Man”

with “Dog.” This example merely scratches the surface of this terrific plugin.

I encourage you to explore its other capabilities.


report erratum • discuss

Find and Replace Across Multiple Files

• 233

Tip 96

Find and Replace Across Multiple Files

The substitute command operates on the current file. So what do we do if we

want to make the same substitution throughout an entire project? Although this

scenario is common, Vim doesn’t include a dedicated command for project-wide

find and replace. We can get this functionality by combining a couple of Vim’s

primitive commands.

We’ll start with a crude but effective solution, and then we’ll look at how it

can be refined. As a demonstration, we’ll use the refactor-project directory, which

you can find in the source files that come distributed with this book. It contains the following files, reproduced here with their contents:



Pragmatic Vim is a hands-on guide to working with Vim.


Pragmatic Vim is written by Drew Neil.


The Pragmatic Bookshelf holds the copyright for this book.



What people are saying about Pragmatic Vim...


Other titles from the Pragmatic Bookshelf...

Each of these files contains the word “Pragmatic,” either as part of the phrase

“Pragmatic Bookshelf” or “Pragmatic Vim.” We’ll do a find and replace to

change each occurrence of “Pragmatic Vim” to “Practical Vim” while leaving

each occurrence of “Pragmatic Bookshelf” unchanged.

If you’d like to follow along, download the source code from Practical Vim’s

book page on the Pragmatic Bookshelf site. Before opening Vim, change to

the refactor-project directory.

The Substitute Command

Let’s start by devising the substitute command. We want to compose a pattern

that matches the word “Pragmatic” when it appears in the phrase “Pragmatic

report erratum • discuss

Chapter 14. Substitution

• 234

Vim” but not when it appears in the phrase “Pragmatic Bookshelf.” This pattern will do the trick:

/Pragmatic\ze Vim

This uses the \ze item to exclude the word “Vim” from the match (see Tip 77,

on page 192). Then we can run this substitute command:


Next we just need to figure out how to execute that command across the entire


Execute a Substitute Command on All Files in the Current Project

In Tip 37, on page 80, we learned that the :argdo command allows us to run

an Ex command in a set of files. We can use this technique to run the substitute command for all files in a project. But first, we must populate the

argument list with all of those files by running this:

:args **/*.txt

We should do one more thing before we continue. Run this:

:set hidden

This setting enables us to navigate away from a modified file without first

saving it. Refer to Tip 37, on page 80, for a more detailed discussion.

Now we can execute our substitution command in all of these files by running


:argdo %s//Practical/g

E486: Pattern not found: Pragmatic\ze Vim

This gets the job done, but Vim reports a “Pattern not found” error in the

output. Remember, some of the files that we’re working with contain the

phrase “Pragmatic Bookshelf” but not “Pragmatic Vim.” So when the substitute

command is executed in these files, Vim throws an error.

The error message is just noise. Vim carries on regardless, executing the

substitute command for each of the remaining files. It’s not critical, but it

can be distracting, especially if we’re dealing with a larger list of files. Supplying the e flag to the substitute command will suppress these error messages.

So we could instead run this:

:argdo %s//Practical/ge

And this way presents fewer distractions.

report erratum • discuss

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tip 95. Swap Two or More Words

Tải bản đầy đủ ngay(0 tr)