开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜