*01* Advanced search and replace This chapter tells some tricks for complex pattern searches and replaces. |01_1| Ignoring case |01_2| Offsets in search patterns |01_3| Regular expressions |01_4| Alternatives |01_5| Character ranges |01_6| Matching a line break |01_7| Example |01_8| Using backreferences =========================================================================== *01_1* Ignoring case By default, Vim's searches are case sensitive. Therefore, "include", "INCLUDE", and "Include" are three different words and a search will match only one of them. If you want your searches to be case-insensitive, you can switch on the 'ignorecase' option > :se ic There is another option which you can set 'smartcase' along with 'ignorecase' > :se ic scs This options makes the search case-insensitive if the pattern contains all lower case patterns. However, if you enter some uppercase characters in your search, it switches to case-sensitive mode. So the following searches gives the following results: pattern matches ~ word word, Word, WORD, WoRd, etc. Word Word WORD WORD WoRd WoRd Switching case sensitiveness per pattern ~ If you want to ignore case or not ignore case for a single search, you can do this by prepending "\c" or "\C" to the search. The behavior is shown in the following table: pattern matches ~ \Cword word \CWord Word \cword word, Word, WORD, WoRd, etc. \cWord word, Word, WORD, WoRd, etc. In these searches, the options 'ignorecase' and 'smartcase' dont matter. =========================================================================== *01_2* Offsets in search patterns You can specify offsets to the search patterns such that the cursor jumps to the offset relative to the match. > // If the offset is a simple number, the cursor will be placed at the beginning of the line that many lines from the match. The offset number can be positive or negative. If it is positive, the cursor moves down that many lines; if negative, it moves up. For eg. > /default/2 This will mode to the second line after the line in which "default" appears. Character offsets ~ You can give character offsets relative to the end of the match in the following manner > /const/e+1 This would move the cursor to 1 character right of the "t" of "const". You can give negative offsets like "e-2" also. You can give offsets relative to the beginning of the match by using "b". > /const/b+2 This would move the cursor to "n" of "const". Repeating search ~ You can repeat the last search by typing > / This repeats the last search with the same offset. If you want to repeat a search but with a different offset, you can use something like > //e To repeat the search removing the offset, type > // Searching backwards ~ You can use all the above commands substituting "/" with a "?" for backward search. However the meaning and the directions of the offsets still remain the same in backward search also. > ?const?e+2 This search will go to the second character after the end of the match. Note: Be careful while using patterns like > /const/-1 Keeping pressing 'n' may bring you the same match again and again. However, character offsets begin the same search not from the cursor position, but from where last match was found. Watch out for this discrepancy. =========================================================================== *01_3* Regular expressions The "*" item specifies that the item before it can match any number of times. Thus: > /a* matches "a", "aa", "aaa", etc. But also "" (the empty string), because zero times is included. The "*" only applies to the item directly before it. Thus "ab*" matches "a", "ab", "abb", "abbb", etc. To match a whole string multiple times, it must be grouped into one item. This is done by putting "\(" before it and "\)" after it. Thus this command: > /\(ab\)* Matches: "ab", "abab", "ababab", etc. And also "". To avoid matching the empty string, use "\+". This makes the previous item match one or more times. > /ab\+ Matches "ab", "abb", "abbb", etc. It does not match "a" when no "b" follows. To match an optional item, use "\=". Example: > /folders\= Matches "folder" and "folders". Specific counts ~ To match a specific number of items use the form "\{n,m}". "n" and "m" are numbers. The item before it will be matched "n" to "m" times (inclusive). Example: > /ab\{3,5} matches "abbb", "abbbb" and "abbbbb". When "n" is omitted, it defaults to zero. When "m" is omitted it defaults to infinity. When ",m" is omitted, it matches exactly "n" times. Examples: pattern match count ~ \{,4} 0, 1, 2, 3 or 4 \{3,} 3, 4, 5, etc. \{0,1} 0 or 1, same as \= \{0,} 0 or more, same as * \{1,} 1 or more, same as \+ \{3} 3 Matching as little as possible ~ The items so far match as many characters as they can find. To match as few as possible, use "\{-n,m}". It works the same as "\{n,m}", except that the minimal amount possible is used. For example, use: > /ab\{-1,3} Will match "ab" in "abbb". Actually, it will never match more than one b, because there is no reason to match more. It requires something else to force it to match more than the lower limit. The same rules apply to removing "n" and "m". It's even possible to remove both of the, resulting in "\{-}". This matches the item before it zero or more times, as few as possible. The item by itself always match zero times. It is useful when combined with something else. Example: > /a.\{-}b This matches "axb" in "axbxb". If this pattern would be used: > /a.*b It would try to match as many characters as possible with ".*", thus it matches "axbxb" as a whole. =========================================================================== *01_4* Alternatives The "or" operator in a pattern is "\|". Example: > /foo\|bar This matches "foo" or "bar". More alternatives can be concatenated: > /one\|two\|three Matches "one", "two" and "three". To match multiple times, the whole thing must be placed in "\(" and "\)": > /\(foo\|bar\)\+ This matches "foo", "foobar", "foofoo", "barfoobar", etc. Another example > /end\(if\|while\|for\) This matches "endif", "endwhile" and "endfor". A related item is "\&". This requires that both alternatives match in the same place. The resulting match uses the last alternative. Example: > /forever\&... This matches "for" in "forever". It will not match "fortuin", for example. =========================================================================== *01_5* Character ranges To match "a", "b" or "c" you could use "/a\|b\|c". When you want to match all alphabets from "a" to "z" this gets very long. There is a shorter method: > /[a-z] The [] construct matches a single character. Inside you specify which characters to match. You can include a list of characters, like this: > /[0123456789abcdef] This will match any of the characters included. For consecutive characters you can specify the range. "0-3" stands for "0123". "w-z" stands for "wxyz". Thus the same command as above can be shortened to: > /[0-9a-f] To match the "-" character itself make it the first or last one in the range. These special characters are accepted to make it easier to use them inside a [] range (they can actually be used anywhere in the search pattern): \e \t \r \b Complimented range ~ To avoid matching a specific character, use "^" at the start of the range. The [] item then matches everything but the characters included. Example: > /"[^"]*" < " a double quote [^"] any character that is not a double quote * as many as possible " a double quote again This matches "foo" and "3!x", including the double quotes. Predefined ranges ~ A number of ranges are used very often. Vim provides a shortcut for these. For example: > /\a Finds alphabetic characters. This is equal to using "/[a-zA-Z]". Here are a few more of these: item matches equivalent ~ \d digit [0-9] \D non-digit [^0-9] \x hex digit [0-9a-fA-F] \X non-hex digit [^0-9a-fA-F] \s white space [ ] ( and ) \S non-white characters [^ ] (not and ) \l lowercase alpha [a-z] \L non-lowercase alpha [^a-z] \u uppercase alpha [A-Z] \U non-uppercase alpha [^A-Z] Note: Using these predefined ranges works a lot faster than the character range it stands for. These items can not be used inside []. Thus "[\d\l]" does NOT work to match a digit or lowercase alpha. Use "\(\d\|\l\)" instead. =========================================================================== *01_6* Matching a line break Vim can find a pattern that includes a line break. You need to specify where the line break happens, because all items mentioned so far don't match a line break. To check for a line break in a specific place, use the "\n" item: > /the\nword This will match at a line that ends in "the" and the next line starts with "word". To match "the word" as well, you need to match a space or a line break. The item to use for it is "\_s": > /the\_sword To allow any amount of white space: > /the\_s\+word This also matches when "the " is at the end of a line and " word" at the start of the next one. "\s" matches white space, "\_s" matches white space or a line break. Similarly, "\a" matches an alphabetic character, and "\_a" matches an alphabetic character or a line break. The other character classes and ranges can be modified in the same way by inserting a "_". Many other items can be made to match a line break by prepending "\_". For example: "\_." matches any character or a line break. Note: "\_.*" matches everything until the end of the file. Be careful with this, it can make a search command very slow. Another example is "\_[]", a character range that includes a line break: > /"\_[^"]*" This finds a text in double quotes that may be split up in several lines. =========================================================================== *01_7* Example One useful example is the search pattern for c style comments > /\/\*\_.\{-}\*\/ How it works: \/ '/' \* '*' \_. Any character including newline \{-} As few as possible \* Trailing '*' \/ Trailing '/' =========================================================================== *01_8* Using backreferences We have seen the command for global search and replace in the basic course. We will try to introduce some tricks that can be used while replacing. Many of these are based on the search patterns discussed above. Reusing searched pattern ~ You have a list of names in this form: Doe, John ~ Smith, Peter ~ You want to change that to: John Doe ~ Peter Smith ~ This can be done with just one command: > :%s/\([^,]*\), \(.*\)/\2 \1/ Let's break this down in parts. Obviously it starts with a substitute command. The "%" is the line range, which stands for the whole file. Thus the substitution is done in every line in the file. The arguments for the substitute command are "/from/to/". The slashes separate the "from" pattern and the "to" string. This is what the "from" pattern contains: \([^,]*\), \(.*\) ~ The first part between \( \) matches "Last" \( \) match anything but a comma [^,] any number of times * matches ", " literally , The second part between \( \) matches "First" \( \) any character . any number of times * In the "to" part we have "\2" and "\1". These are called backreferences. They refer to the text matched by the \( \) parts in the pattern. "\2" refers to the text matched by the second "\( \)", which is the "First" name. "\1" refers to the first \( \), which is the "Last" name. You can use up to nine backreferences in the "to" part of a substitute command. "\0" stands for the whole matched pattern. "&" can also be used instead. Note: You can actually use the backreferences any time after they are defined; even in the search pattern itself. For eg. you can use this search pattern for finding repeated words in your text > /\([0-9a-zA-Z_-]\+\)\_s\+\1 Again breaking it down /\([0-9a-zA-Z_-]\+\)\_s\+\1 \([0-9a-zA-Z_-]\+\) The first group for backreference [0-9a-zA-Z_-]\+ The word characters more than once \_s\+ Any white space including newline \1 The first group again! =========================================================================== vim:ft=help:tw=76:ts=8:nomodifiable