Challenge "Simple text editing with Vim" at VimGolf: How does the #1 solution work?
Simple text editing with Vim: http://vimgolf.com/challenges/4d1a34ccfa85f32065000004
I find it difficult to un开发者_如何学Pythonderstand the #1 solution (Score 13).
Sorry, no solution is pasted in this post, because I don't know if it's appropriate to do that.
The solution is centered on the :g
command. From the help:
:g :global E147 E148
:[range]g[lobal]/{pattern}/[cmd]
Execute the Ex command [cmd] (default ":p") on the
lines within [range] where {pattern} matches.
So basically, the solution executes some ex commands on lines that have a "V", which are exactly the ones that need editing. You probably noticed that earlier solutions rely on duplicating the lines, rather than really changing them. This solution specially shows an interesting pattern:
3jYjVp3jYjVp3jYjVpZZ
^ ^ ^
Which could be reduced with a macro:
qa3jYjVpq3@aZZ
The solution using the :g
command does basically the same thing. The first
command executed is t.
. From the help:
:t
:t Synonym for copy.
:[range]co[py] {address} :co :copy
Copy the lines given by [range] to below the line
given by {address}.
The address given was .
, which means current line:
Line numbers may be specified with: :range E14 {address}
{number} an absolute line number
. the current line :.
$ the last line in the file :$
% equal to 1,$ (the entire file) :%
't position of mark t (lowercase) :'
'T position of mark T (uppercase); when the mark is in
another file it cannot be used in a range
/{pattern}[/] the next line where {pattern} matches :/
?{pattern}[?] the previous line where {pattern} matches :?
\/ the next line where the previously used search
pattern matches
\? the previous line where the previously used search
pattern matches
\& the next line where the previously used substitute
pattern matches
So the ex command t.
means "copy current line to below the current line".
Then, there is a bar which:
:bar :\bar
'|' can be used to separate commands, so you can give multiple commands in one
line. If you want to use '|' in an argument, precede it with '\'.
And the d
command, which obviously deletes the line. It was given a range of
+
, meaning the "current line + 1". You could pass .+1
but +
for short.
These info can be read surrounding the help for :range
:
The default line specifier for most commands is the cursor position, but the
commands ":write" and ":global" have the whole file (1,$) as default.
Each may be followed (several times) by '+' or '-' and an optional number.
This number is added or subtracted from the preceding line number. If the
number is omitted, 1 is used.
And that's it.
:g/V/t.|+d<CR>ZZ
On every line that has a "V", copy it down and delete the next line. Write and quit.
One thing that I didn't mention is why the :g
commands are executed three times instead of 6 or even more (lines are duplicated along the process). The :g
command starts positioning the cursor on line one, and goes down to $. But if the commands change the current line, :g
continues from there. So:
:g/V/
Current line is 4. Now:
t.
This moves the cursor to line 5. And then:
+d
Deletes line 6, the cursor remain in 5. So the next :g
match will be in line 8.
精彩评论