vimtricks.wiki Concise Vim tricks, one at a time.

How do I search for a pattern that spans multiple lines?

Answer

/foo\_.*bar

Explanation

Vim's default . in regex matches any character except a newline, so a pattern like /foo.*bar only finds matches on a single line. By using \_.* instead of .*, you tell Vim that the dot should also match newline characters, allowing your search to span across line boundaries.

How it works

  • \_ is a modifier that makes the next character class also match \n (newline)
  • \_. means "any character including newline" (compared to . which excludes newlines)
  • \_.* matches any number of characters across any number of lines
  • So /foo\_.*bar finds foo followed by bar anywhere later in the file, even across multiple lines

Example

Given the text:

function foo() {
    let x = 1;
    return bar(x);
}

Searching with /foo.*bar finds nothing because foo and bar are on different lines.

Searching with /foo\_.*bar matches from foo on line 1 all the way to bar on line 3, highlighting the entire multi-line span.

Common multi-line patterns

" Find an opening HTML tag followed by its closing tag (across lines)
/<div\_.*<\/div>

" Find a function signature followed by a return statement
/function\_.*return

" Match an if-block opening to its closing brace
/if (\_.*}

Tips

  • Use \_.\{-} for a non-greedy multi-line match (equivalent to .*? in Perl regex): /foo\_.\{-}bar matches the shortest span from foo to the nearest bar
  • Without \{-}, \_.* is greedy — it matches from the first foo to the last bar in the entire file
  • The \_ modifier works with character classes too: \_s matches any whitespace including newlines, \_[a-z] matches lowercase letters or newlines
  • Combine with substitution for multi-line replacements: :%s/foo\_.*bar/replacement/g — but be careful with greedy matching
  • In very magic mode (\v), you still need \_ for newline-spanning: /\vfoo\_.{-}bar
  • Multi-line search can be slow on very large files because Vim must scan across line boundaries — use \_.\{-} (non-greedy) whenever possible to limit the scan
  • Use \n in the search pattern to match a literal newline character at a specific point: /foo\nbar matches foo at the end of one line immediately followed by bar at the start of the next

Next

How do I edit multiple lines at once using multiple cursors in Vim?