Vim: Searching
This is part 5 of a series of tutorial to Vim. You can read Part 4 here.
/
If you ever found yourself using a program which shows text in terminal, and you
want to search something, the first guess you want to make is /
. The key /
will work, by default, for several programs1: less, more, tmux2, even Firefox.
To state it explicitly, the way to search in Vim is by pressing /
(obviously in normal mode),
followed by keywords you want to search for and then hit return (enter).
Lesson 6
/
searches for keywords.
/
works for searching in several other programs including less, more, git status
,
Firefox. When in doubt about how to search, press /
in any unfamiliar program.
- Very soon, we'll boost Vim to enable fancy features such as eager search-searching as we enter keywords, highlighting all the matched words, etcetera.
- Press
n
to jump to next matched item.N
to go to previous matched item (adding shift reverses the action)
- Or press
<shift>-/
(?
) to search backwards.
Regex
No search system is worth its salt if doesn't support regex. Vim considers its users to be power users and enables regex by default. The symbols might be a little different, from what you are used to, but you will find support for all the rules you demand. If you are unfamiliar with Regular Expressions, also called as 'regex', here's a 5 line crash course on regex:
- Regex are patterns of characters used to match strings which conform to certain well defined patterns or rules.
*
is a greedy quantifier, it will match character preceding it to 0 or more characters in text.- Example will illustrate this better:
ba*
will match 'b', 'ba', 'baa', 'baaa', 'baaaaaaaaaaaa', …
+
is same as*
, except it matches 1 or moreba+
will match 'ba', 'baaa' but not 'b'
- Example will illustrate this better:
.
will match any single characterb.t
will match any of 'bit', 'bat', 'but', 'bot', 'b4t', 'b%t', …
- Characters except quantifiers as shown above (there are more than these),
match to themself.
help
will match 'help', nothing else- To search for characters which denote quantifiers, you have to escape them
using a backslash
\
bit\.
will match just 'bit.' and nothing else.
[...]
will match any one of the characters inside '[' and ']'[1234567890]
will match any single digit- above rule can be shorten as
[0-9]
similar to[a-zA-Z]
to match characters in range a-z. - append a
+
and you have regex rule to search for numbers greater than 9.
Vim supports much more regex rules than what's stated above, its language is bigger than Regular Languages-it supports positive look ahead, negative look behind etc3. It also supports capturing and back referencing, which is discussed next.
Substitution on Steriods
The way to replace foo
with bar
in Vim is:
:%s/foo/bar/gc
Now, one might think that's too complex for substituting since in most of other editors
you can simply press <ctrl>+r
, foo
and bar
. But, if you spend enough time
with Vim, you will realize Vim has generic command pattern and substitute is just
following that. Once you get hang of the generic pattern, applying any command is actually
very simply.
Let's dissect the substitute command:
:%s/foo/bar/gc
:
tells vim to accept command%
runs command over the whole file- we could have specified other range explicitly such as
12,34
(from line 12 to 34) - stating range is very helpful in places where you want to target the substitution.
- it may help to eliminate the
c
flag, and thus the labor of pressing 'y' for each subsitution
- it may help to eliminate the
- we could have specified other range explicitly such as
s
s stands for substitute, since that's what we are doing here- we'll also look at more powerful command
g
later
- we'll also look at more powerful command
foo
what we are searching forbar
what to substitute withg
andc
are optional flags which meang
global: substitute multiple instances offoo
on same linec
confirm: prompt for confirmation before substituting.- these flags are needed most of the time, but not always.
Regex
- Regular Expression can be very helpful for substitution too. You can 'capture' patterns and then later use them while substituting.
Here's an example:
1: var fun1 = function () { 2: return "I am fun1"; 3: }; 4: var fun2 = function () { 5: return "I am fun2"; 6: }; 7: var fun3 = function () { 8: return "I am fun3"; 9: };
suppose we want to refactor
var funx = function () {
tofunction funx() {
, that is:function fun1 () { return "I am fun1"; }; function fun2 () { return "I am fun2"; }; function fun3 () { return "I am fun3"; };
- Clearly, just a small part of line is different- the function name, rest is same. We can use regex to capture the varying part and use that in substitute.
- So, let's write regex for capturing funx:
var (\w+) = function () {
- by capturing a pattern, we can 'back reference' it later.
- we can back reference captured patterns, using \1 for first, \2 for second and so on.
thus we can refactor by executing:
:%s/var \(\w\+\) = function () {/function \1 () {/ |←regex→| | | ↪ Backreference | ← old → || ← new → |
- Expression labeled as 'regex' is actually regex capturing pattern.
- In
(\w+)
, we have to escape(
,+
and)
. Without escaping, Vim would try to match them with literal characters '(', '+' and ')'.
- In
- Expression labeled as 'regex' is actually regex capturing pattern.
- Just to illustrate the convenience of specifying the range, consider a slightly
different problem: we want to refactor the first two functions only. There
are two ways of doing it:
- we can append
c
flag to prompt us before every substitution, so that we can say 'no' when it tries to substitute the third time.- but what happens if there are 100 functions before
fun1
, we'll have to hitn
100 times just to reachfun1
- but what happens if there are 100 functions before
- we can specify the exact range.
here, it will be
1,6
4. Thus the command can be re written as::1,6s/var \(\w\+\) = function () {/function \1 () {/
- we can append
Lesson 7
Substitute command
:[range]s/<old>/<new>/[optional flags]
Specifying precise range is better than c
flag. It saves unintentional changes and manual work.
Remember to use regular expressing and capture the patterns which differ. Use back referencing to refer captured expression and then use them while substituting.
One More thing
If you have followed along the refactoring example by trying out in Vim, which
BTW you should do, you will notice that the code indentation became very messy.
Let me introduce to you a little operator =
, this does an amazing job of auto
aligning the code. =
is composable as any other commands, you can say
=G
to auto indent till end of buffer, thus if you are at beginning this will auto indent whole buffer.==
to indent current line or=4<downarrow>
to indent next 4 lines.
If that doesn't work as expected, you can manually, but effortlessly, indent lines
using >
and <
operator to indent and outdent lines respectively. And of couse
these guys are composable too.
Footnotes:
I'm not entirely sure, if other programs have Vim's binding or Vim picked up famous bindings
tmux is Terminal Multiplexer, it pairs very well with Vim to make a complete Development environment.
This site: http://www.vimregex.com/, should satisfy all your hunger for advanced regex rules.
1,4
would have been more precise.