Vim Tips Wiki
Register
(tweaks + incorporate recent comments (I think all covered, so I removed the comments))
(Change <tt> to <code>, perhaps also minor tweak.)
Line 11: Line 11:
 
|category2=
 
|category2=
 
}}
 
}}
Vim can search for text that spans multiple lines. For example, the search <tt>/hello\_sworld</tt> finds "hello world" in a single line, and also finds "hello" ending one line, with "world" starting the next line. In a search, <tt>\s</tt> finds space or tab, while <tt>\_s</tt> finds newline or space or tab: an underscore adds a newline to any character class.
+
Vim can search for text that spans multiple lines. For example, the search <code>/hello\_sworld</code> finds "hello world" in a single line, and also finds "hello" ending one line, with "world" starting the next line. In a search, <code>\s</code> finds space or tab, while <code>\_s</code> finds newline or space or tab: an underscore adds a newline to any character class.
   
This tip shows how to search over multiple lines, and presents a useful command so entering <tt>:S&nbsp;hello&nbsp;world</tt> finds "hello" followed by "world" separated by spaces or tabs or newlines, and <tt>:S!&nbsp;hello&nbsp;world</tt> allows any non-word characters, including newlines, between the words.
+
This tip shows how to search over multiple lines, and presents a useful command so entering <code>:S&nbsp;hello&nbsp;world</code> finds "hello" followed by "world" separated by spaces or tabs or newlines, and <code>:S!&nbsp;hello&nbsp;world</code> allows any non-word characters, including newlines, between the words.
   
 
==Patterns including end-of-line==
 
==Patterns including end-of-line==
The search <tt>/^abc</tt> finds <tt>abc</tt> at the beginning of a line, and <tt>/abc$</tt> finds <tt>abc</tt> at the end of a line. However, in <tt>/abc^def</tt> and <tt>/abc$def</tt> the <tt>^</tt> and <tt>$</tt> are just ordinary characters with no special meaning. By contrast, each of the following has a special meaning anywhere in a search pattern.
+
The search <code>/^abc</code> finds <code>abc</code> at the beginning of a line, and <code>/abc$</code> finds <code>abc</code> at the end of a line. However, in <code>/abc^def</code> and <code>/abc$def</code> the <code>^</code> and <code>$</code> are just ordinary characters with no special meaning. By contrast, each of the following has a special meaning anywhere in a search pattern.
   
 
{| class="cleartable"
 
{| class="cleartable"
| <tt>\n</tt> || a newline character (line ending)
+
| <code>\n</code> || a newline character (line ending)
 
|-
 
|-
| <tt>\_s</tt> || a whitespace (space or tab) or newline character
+
| <code>\_s</code> || a whitespace (space or tab) or newline character
 
|-
 
|-
| <tt>\_^</tt> || the beginning of a line (zero width)
+
| <code>\_^</code> || the beginning of a line (zero width)
 
|-
 
|-
| <tt>\_$</tt> || the end of a line (zero width)
+
| <code>\_$</code> || the end of a line (zero width)
 
|-
 
|-
| <tt>\_.</tt> || any character including a newline
+
| <code>\_.</code> || any character including a newline
 
|}
 
|}
   
 
Example searches:
 
Example searches:
;<tt>/abc\n*def</tt>
+
;<code>/abc\n*def</code>
:Finds <tt>abc</tt> followed by zero or more newlines then <tt>def</tt>.
+
:Finds <code>abc</code> followed by zero or more newlines then <code>def</code>.
:Finds <tt>abcdef</tt> or <tt>abc</tt> followed by blank lines and <tt>def</tt>.
+
:Finds <code>abcdef</code> or <code>abc</code> followed by blank lines and <code>def</code>.
 
:The blank lines have to be empty (no space or tab characters).
 
:The blank lines have to be empty (no space or tab characters).
   
;<tt>/abc\_s*def</tt>
+
;<code>/abc\_s*def</code>
:Finds <tt>abc</tt> followed by any whitespace or newlines then <tt>def</tt>.
+
:Finds <code>abc</code> followed by any whitespace or newlines then <code>def</code>.
:Finds <tt>abcdef</tt> or <tt>abc</tt> followed by blank lines and <tt>def</tt>.
+
:Finds <code>abcdef</code> or <code>abc</code> followed by blank lines and <code>def</code>.
 
:The blank lines can contain any number of space or tab characters.
 
:The blank lines can contain any number of space or tab characters.
:There may be whitespace after <tt>abc</tt> or before <tt>def</tt>.
+
:There may be whitespace after <code>abc</code> or before <code>def</code>.
   
;<tt>/abc\_$\_s*def</tt>
+
;<code>/abc\_$\_s*def</code>
:Finds <tt>abc</tt> at end-of-line followed by any whitespace or newlines then <tt>def</tt>.
+
:Finds <code>abc</code> at end-of-line followed by any whitespace or newlines then <code>def</code>.
:There must be no characters (other than a newline) following <tt>abc</tt>.
+
:There must be no characters (other than a newline) following <code>abc</code>.
:There can be any number of space, tab or newline characters before <tt>def</tt>.
+
:There can be any number of space, tab or newline characters before <code>def</code>.
   
;<tt>/abc\_s*\_^def</tt>
+
;<code>/abc\_s*\_^def</code>
:Finds <tt>abc</tt> followed by any whitespace or newlines then <tt>def</tt> where <tt>def</tt> begins a line.
+
:Finds <code>abc</code> followed by any whitespace or newlines then <code>def</code> where <code>def</code> begins a line.
:There must be no characters (other than a newline) before <tt>def</tt>.
+
:There must be no characters (other than a newline) before <code>def</code>.
:There can be any number of space, tab or newline characters after <tt>abc</tt>.
+
:There can be any number of space, tab or newline characters after <code>abc</code>.
   
;<tt>/abc\_$def</tt>
+
;<code>/abc\_$def</code>
:Finds nothing because <tt>\_$</tt> is "zero width" so the search is looking for <tt>abcdef</tt> where <tt>abc</tt> is also at end-of-line (which cannot occur).
+
:Finds nothing because <code>\_$</code> is "zero width" so the search is looking for <code>abcdef</code> where <code>abc</code> is also at end-of-line (which cannot occur).
   
;<tt>/abc\_^def</tt>
+
;<code>/abc\_^def</code>
:Finds nothing because <tt>\_^</tt> is "zero width" so the search is looking for <tt>abcdef</tt> where <tt>def</tt> is also at beginning-of-line (which cannot occur).
+
:Finds nothing because <code>\_^</code> is "zero width" so the search is looking for <code>abcdef</code> where <code>def</code> is also at beginning-of-line (which cannot occur).
   
;<tt>/abc\_.\{-}def</tt>
+
;<code>/abc\_.\{-}def</code>
:Finds <tt>abc</tt> followed by any characters or newlines (as few as possible) then <tt>def</tt>.
+
:Finds <code>abc</code> followed by any characters or newlines (as few as possible) then <code>def</code>.
:Finds <tt>abcdef</tt> or <tt>abc</tt> followed by any characters then <tt>def</tt>.
+
:Finds <code>abcdef</code> or <code>abc</code> followed by any characters then <code>def</code>.
   
 
==Searching for multiline HTML comments==
 
==Searching for multiline HTML comments==
Line 74: Line 74:
 
</pre>
 
</pre>
   
The atom <tt>\_.</tt> finds any character including end-of-line. The multi <tt>\{-}</tt> matches as few as possible (stopping at the first "<tt>--></tt>"; the multi <tt>*</tt> is too greedy and would stop at the last occurrence).
+
The atom <code>\_.</code> finds any character including end-of-line. The multi <code>\{-}</code> matches as few as possible (stopping at the first "<code>--></code>"; the multi <code>*</code> is too greedy and would stop at the last occurrence).
   
 
Syntax highlighting may be not be accurate, particularly with long comments. The following command will improve the accuracy when jumping in the file, but may be slower ({{help|:syn-sync}}):
 
Syntax highlighting may be not be accurate, particularly with long comments. The following command will improve the accuracy when jumping in the file, but may be slower ({{help|:syn-sync}}):
Line 82: Line 82:
   
 
==Searching over multiple lines==
 
==Searching over multiple lines==
A pattern can find any specified characters, for example, <tt>[aeiou]</tt> matches 'a' or 'e' or 'i' or 'o' or 'u'. In addition, Vim defines several character classes. For example, <tt>\a</tt> is <tt>[A-Za-z]</tt> (matches any alphabetic character), and <tt>\A</tt> is <tt>[^A-Za-z]</tt> (opposite of <tt>\a</tt>; matches any non-alphabetic character). {{help|/\a}}
+
A pattern can find any specified characters, for example, <code>[aeiou]</code> matches 'a' or 'e' or 'i' or 'o' or 'u'. In addition, Vim defines several character classes. For example, <code>\a</code> is <code>[A-Za-z]</code> (matches any alphabetic character), and <code>\A</code> is <code>[^A-Za-z]</code> (opposite of <code>\a</code>; matches any non-alphabetic character). {{help|/\a}}
   
An underscore can be used to extend a character class to include a newline (end of line). For example, searching for <tt>\_[aeiou]</tt> finds a newline or a vowel, so <tt>\_[aeiou]\+</tt> matches any sequence of vowels, even a sequence spanning multiple lines. Similarly, <tt>\_a\+</tt> matches any sequence of alphabetic characters, even when spanning multiple lines.
+
An underscore can be used to extend a character class to include a newline (end of line). For example, searching for <code>\_[aeiou]</code> finds a newline or a vowel, so <code>\_[aeiou]\+</code> matches any sequence of vowels, even a sequence spanning multiple lines. Similarly, <code>\_a\+</code> matches any sequence of alphabetic characters, even when spanning multiple lines.
   
 
The following search pattern finds "hello world" where any non-alphabetic characters separate the words:
 
The following search pattern finds "hello world" where any non-alphabetic characters separate the words:
Line 91: Line 91:
 
</pre>
 
</pre>
   
The above pattern (which is equivalent to <tt>hello\_A*world</tt>) matches "helloworld", and "hello? ... world", and similar strings, even if "hello" is on one line and "world" is on a following line.
+
The above pattern (which is equivalent to <code>hello\_A*world</code>) matches "helloworld", and "hello? ... world", and similar strings, even if "hello" is on one line and "world" is on a following line.
   
 
==Searching over multiple lines with a user command==
 
==Searching over multiple lines with a user command==
The script below defines the command <tt>:S</tt> that will search for a phrase, even when the words are on different lines. Examples:
+
The script below defines the command <code>:S</code> that will search for a phrase, even when the words are on different lines. Examples:
   
;<tt>:S hello world</tt>
+
;<code>:S hello world</code>
 
:Searches for "hello" followed by "world", separated by whitespace including newlines.
 
:Searches for "hello" followed by "world", separated by whitespace including newlines.
;<tt>:S! hello world</tt>
+
;<code>:S! hello world</code>
 
:Searches for "hello" followed by "world", separated by any non-word characters (whitespace, newlines, punctuation).
 
:Searches for "hello" followed by "world", separated by any non-word characters (whitespace, newlines, punctuation).
 
:Finds, for example, "hello, world" and "hello+world" and "hello ... world". The words can be on different lines.
 
:Finds, for example, "hello, world" and "hello+world" and "hello ... world". The words can be on different lines.
   
After entering the command, press <tt>n</tt> or <tt>N</tt> to search for the next or previous occurrence.
+
After entering the command, press <code>n</code> or <code>N</code> to search for the next or previous occurrence.
   
Put the following in your [[vimrc]] (or in file <tt>searchmultiline.vim</tt> in your plugin directory):
+
Put the following in your [[vimrc]] (or in file <code>searchmultiline.vim</code> in your plugin directory):
 
<source lang="vim">
 
<source lang="vim">
 
" Search for the ... arguments separated with whitespace (if no '!'),
 
" Search for the ... arguments separated with whitespace (if no '!'),

Revision as of 07:49, 11 July 2012

Tip 242 Printable Monobook Previous Next

created 2002 · complexity intermediate · version 6.0


Vim can search for text that spans multiple lines. For example, the search /hello\_sworld finds "hello world" in a single line, and also finds "hello" ending one line, with "world" starting the next line. In a search, \s finds space or tab, while \_s finds newline or space or tab: an underscore adds a newline to any character class.

This tip shows how to search over multiple lines, and presents a useful command so entering :S hello world finds "hello" followed by "world" separated by spaces or tabs or newlines, and :S! hello world allows any non-word characters, including newlines, between the words.

Patterns including end-of-line

The search /^abc finds abc at the beginning of a line, and /abc$ finds abc at the end of a line. However, in /abc^def and /abc$def the ^ and $ are just ordinary characters with no special meaning. By contrast, each of the following has a special meaning anywhere in a search pattern.

\n a newline character (line ending)
\_s a whitespace (space or tab) or newline character
\_^ the beginning of a line (zero width)
\_$ the end of a line (zero width)
\_. any character including a newline

Example searches:

/abc\n*def
Finds abc followed by zero or more newlines then def.
Finds abcdef or abc followed by blank lines and def.
The blank lines have to be empty (no space or tab characters).
/abc\_s*def
Finds abc followed by any whitespace or newlines then def.
Finds abcdef or abc followed by blank lines and def.
The blank lines can contain any number of space or tab characters.
There may be whitespace after abc or before def.
/abc\_$\_s*def
Finds abc at end-of-line followed by any whitespace or newlines then def.
There must be no characters (other than a newline) following abc.
There can be any number of space, tab or newline characters before def.
/abc\_s*\_^def
Finds abc followed by any whitespace or newlines then def where def begins a line.
There must be no characters (other than a newline) before def.
There can be any number of space, tab or newline characters after abc.
/abc\_$def
Finds nothing because \_$ is "zero width" so the search is looking for abcdef where abc is also at end-of-line (which cannot occur).
/abc\_^def
Finds nothing because \_^ is "zero width" so the search is looking for abcdef where def is also at beginning-of-line (which cannot occur).
/abc\_.\{-}def
Finds abc followed by any characters or newlines (as few as possible) then def.
Finds abcdef or abc followed by any characters then def.

Searching for multiline HTML comments

It is common for comments in HTML documents to span several lines:

<!-- This comment
 covers two lines. -->

The following search finds any HTML comment:

/<!--\_.\{-}-->

The atom \_. finds any character including end-of-line. The multi \{-} matches as few as possible (stopping at the first "-->"; the multi * is too greedy and would stop at the last occurrence).

Syntax highlighting may be not be accurate, particularly with long comments. The following command will improve the accuracy when jumping in the file, but may be slower (:help :syn-sync):

:syntax sync fromstart

Searching over multiple lines

A pattern can find any specified characters, for example, [aeiou] matches 'a' or 'e' or 'i' or 'o' or 'u'. In addition, Vim defines several character classes. For example, \a is [A-Za-z] (matches any alphabetic character), and \A is [^A-Za-z] (opposite of \a; matches any non-alphabetic character). :help /\a

An underscore can be used to extend a character class to include a newline (end of line). For example, searching for \_[aeiou] finds a newline or a vowel, so \_[aeiou]\+ matches any sequence of vowels, even a sequence spanning multiple lines. Similarly, \_a\+ matches any sequence of alphabetic characters, even when spanning multiple lines.

The following search pattern finds "hello world" where any non-alphabetic characters separate the words:

hello\_[^a-zA-Z]*world

The above pattern (which is equivalent to hello\_A*world) matches "helloworld", and "hello? ... world", and similar strings, even if "hello" is on one line and "world" is on a following line.

Searching over multiple lines with a user command

The script below defines the 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).
Finds, for example, "hello, world" and "hello+world" and "hello ... world". The words can be on different lines.

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>

See also

References

Comments