Thomas Damgaard's Blog

Search and Replace across multiple lines with Vim

24 June 2022 - Thomas Damgaard

I recently had a file open in Vim with a bunch of lines that has been wrapped by an email client

Let’s say, a line I was concerned about looked like this:

012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789

Now, these lines looked like this:

01234567890123456789012345678901234567890123456789012345678901234567890123456=^M
7890123456789

I needed to join those two lines back into the full line and remove the =^M that had been inserted.

But how do you join lines with Vim’s search and replace? Having used Vim for more than two decades, I didn’t know.

As it turns out, this is really easy and I’m a bit embarrassed that I didn’t know.

Here is how you do it: You just put in \n in the pattern you are searching for.

Example:

:%s/=^M\n//

The above solved it for me. Here is how it works:

Now, this solved the issue for me. I didn’t really have to search across line boundaries as the newline character is part of the line that contains the rest of the pattern. However, this lead me to the idea of searching and replacing across line boundaries. And it works!

Example with some random code:

fibonacci_heap(fibonacci_heap && rhs):
    super_t(std::move(rhs)), top_element(rhs.top_element)
{
    roots.splice(roots.begin(), rhs.roots);
    rhs.top_element = NULL;
}

So we can no search for )\n{\n roots and replace with ) { roots with the following command:

:s/:\n{\n    roots/) { roots/

This results in:

fibonacci_heap(fibonacci_heap && rhs):
    super_t(std::move(rhs)), top_element(rhs.top_element) { roots.splice(roots.begin(), rhs.roots);
    rhs.top_element = NULL;
}

(sorry, I did not have time to think of a good example but I am sure there actual a good use cases for this)

Filed under: tips, vim