Wednesday, February 16, 2011

Vim Usage: mastering the replace function

Replacing text is a daily using for text editing. For most visual editor, you probably can click edit->replace to achieve the goal. Right now, it maybe a hard time that you have to do it in vim. What you need to remember is ":s" which stands for substitution. To use it, you need to provide the search text and replace text like ":s/abc/123". When you press enter, you may not be satisfied. This command means to substitute first occurred "abc" with "123" in current line. If you want to do it in whole line, you need to put one more parameter (/g). Thus the command is ":s/abc/123/g" which is substituting "abc" with "123" globally within the line.

In fact, vim provides lots of flexibility for users. You can combine this with range. That means you can replace text within a range of lines. You can type ":n, $s/abc/123" which replace the first occurrence of "abc" to "123" for each line in the range. If you need to replace all occurrence between line n and the end of file, you should use ":n,$s/abc/123/g" to replace them globally from line n to the end. Remember, "n" is line no, if you want to set the range from current line to the end of file, you can use ".". "." is a very useful key in vim.

Now, you may want to replace within whole file. You may think you can use ":1,$s/abc/123" to specify replace from line 1 to end line. However, you can use other one if you like to save some key strokes. ":%s/abc/123" is to replace first occurred "abc" with "123" in every line. ":%s/abc/123/g" is to replace all "abc" with "123" in every line. (Actually, if you want, you may want to remember two more which do the same action: ":g/abc/s//123" and ":g/abc/s//123/g")

Last problem, what if I want to replace the text with "/"? Should I use ":s/abc//123//" to replace "abc/" with "123/"? However, "/" in this command is used for separator and vim can't interpret this command definitely. Luckily, vim doesn't force you to use "/" with separator. You can use "#" or "+".  For example, to replace "/home/user1" with "/home/user2", you can use ":s#/home/user1#/home/user2#g" or ":s+/home/user1+/home/user2+g".

Conclusion:
If you just need to find a function which is same as replace function in usual editors, ":%s/target/replace/g" is enough for you.

Summary:
  • ":s/abc/123" - replace first occurred "abc" with "123" in current line
  • ":s/abc/123/g" - replace all "abc" with "123" in current line
  • ":n, $s/abc/123" - replace first occurred "abc" with "123" from line n to end of file
  • ":n, $s/abc/123/g" - replace all "abc" with "123" from line n to end of file
  • ":., $s/abc/123/g" - replace all "abc" with "123" from current line to end of file
  • ":%s/abc/123" - replace first occurred "abc" with "123" in every line
  • ":%s/abc/123/g" - replace all "abc" with "123" in every line

Remark:
Do you remember that you have introduced two commands to convert dos format file to *nix format? One is using vim to set the encoding and the other one is using dos2unix command. Huh........you actually can do that using replace function in vim. First, what is the different between dos format and *nix format file? The answer is that the new line characters are different in the system. DOS uses (0A0D) to represent the end of line while *nix uses (0A) to represent a new line. Thus, if you are viewing a dos file in, you will see many "^M" in the end of each line which is a extra character for windows to know that which is a new line. [Vice versa, if you are viewing *nix file under windows, you may see whole file concatenated in one line if you are using notepad. The reason is that windows doesn't know it is a time to change to new line without (0D)]

Now, you know what the problem is and for sure, what you need to do is to delete all "^M" in the document. Thus, please use ":%s/^M//g" in command mode. Be careful, here "^" is not same as shift 6. You need to type: ":%s/[ctrl-v][ctrl-M]//g".

No comments:

Post a Comment