Search across multiple lines
From Vim Tips Wiki
Tip 242 Previous Next created 2002 · complexity intermediate · author vim_power · version 6.0
One of the most uncelebrated features of Vim is the ability to span a search across multiple lines.
All of the following match line beginnings or endings anywhere in the search pattern, unlike ^ and $.
| \n | the newline character itself |
| \_^ | the beginning of a line |
| \_$ | the end of a line but before any newline character |
| \_s | a space, tab character, or newline character |
For example, /{\_s finds { followed by a whitespace or newline character.
Some of these can be confusing to work with. For example, this works as expected:
end one line\_^begin the next
\_$ is not equivalent. It also is a zero-length marker, but that means the end-of-line characters remain between it and the next line. The following never matches, because u doesn't match the end-of-line character.
end one line\_$um
This does what you want:
end one line\nnext line
\_s is a different kind of beast. You can insert the underscore in any of the character-class atoms to include line-ends in the class. In this case the match position moves past a line-end when it matches. This means you can search for things like \_S\+ to match any sequence of NON-whitespace characters, even across multiple lines, or \_[abc] to match sequences of characters containing only the letters a, b, or c, that can span multiple lines.
The last member of the set is \_., which matches any character in the buffer, including line-ends. \_.* matches the rest of the buffer from the current position. Use this with caution, because it can easily match much more than you want or slow down your search considerably. Consider using a non-greedy search (\_.\{-}) instead.
Contents |
[edit] See also
- Search for visually selected text to search for selected text; finds targets on multiple lines
[edit] References
[edit] Comments
TO DO
- Fix TOC (put a short intro at top with a new heading for the bulk of the tip).
- Check following.
- Re "search for html comments": I quickly merged this without much thought, and there is more to do. There is sure to be one good regex to do what is wanted.
- Re blanksearch: I replaced the Python code (and omitted the link to some Vim script), and renamed the function to SearchMultiLine.
- After checking, need to put following into tip.
With a little more work, this might be the next featured tip. :S! is very clever. JohnBeckett 04:24, November 8, 2009 (UTC)
[edit] Search for HTML comments that cover multiple lines
The following search finds HTML comments that cover one or more lines:
/<!--\_p\{-}-->
Example comment:
<!-- This comment covers multiple lines. -->
We used \{-} the "few as possible" operator rather than * which is too greedy when there are many such comments in the file.
The key is of course \_p which is printable characters including EOL end-of-lines.
However, the highlighting is very erratic when the span over number of lines exceeds, say, 30. And highlighting is rather spotty when there are shifts in screen views. This is due to the default that improves highlighting performance.
If you want to ensure the most accurate highlighting, try:
:syntax sync fromstart
This can slow things down on large files with complex highlighting. :help :syn-sync
Comments that include tab characters (for example, as indents) are not found by the above because \_p matches printable characters and newline, but not tab).
Here's another way to highlight HTML comments using conventional regex:
/<\!--\(.\|\n\)\{-}-->
[edit] Search for words over multiple lines
The script below defines command :S that will search for a phrase, even when the words are on different lines. Examples:
- :S hello world
- Searches for "hello" followed by "world", separated by whitespace including newlines.
- :S! hello world
- Searches for "hello" followed by "world", separated by any non-word characters (whitespace, newlines, punctuation).
After entering the command, press n or N to search for the next or previous occurrence.
Put the following in your vimrc (or in file searchmultiline.vim in your plugin directory):
" Search for the ... arguments separated with whitespace (if no '!'),
" or with non-word characters (if '!' added to command).
function! SearchMultiLine(bang, ...)
if a:0 > 0
let sep = (a:bang) ? '\_W\+' : '\_s\+'
let @/ = join(a:000, sep)
endif
endfunction
command! -bang -nargs=* -complete=tag S call SearchMultiLine(<bang>0, <f-args>)|normal! /<C-R>/<CR>
