Sunday, April 17, 2011

Can I transpose a file in vim?

I know I can use awk but I am on a windows box I am making a function for others that may not have awk. I also know I can write a C program but I would love not have to create maintain and compile something for a little vim utility I am making.

THe original file might be

THE DAY WAS LONG 
THE WAY WAS FAST

and it would become

TT
HH
EE

DW
AA
YY

WW
AA
SS

LF
OA
NS
GT

UPDATE: Golf rules apply to selecting correct answer.

UPDATE: Python fans should check out Mr. Duffy's answer below.

From stackoverflow
  • Vim support for a number of scripting languages built in -- see the Python interface as an example.

    Just modify vim.current.buffer appropriately and you're set.

    To be a little more specific:

    function! Rotate()
    python <<EOF
    import vim, itertools
    max_len = max((len(n) for n in vim.current.buffer))
    
    vim.current.buffer[:] = [
        ''.join(n) for n in itertools.izip(
         *( n + ' ' * (max_len - len(n))
            for n in vim.current.buffer))]
    EOF
    endfunction
    
    ojblass : Sweet Jesus look at all all that! So much text manipulation goodness!
    guns : ++ oooh - was unaware that vim supported more than vimscript! Also perl, tcl, and ruby -- awesome!
    Mykola Golubyev : It supports those scripts but not by default. You have to turn them on during build.
    Charles Duffy : Right. Just about every distribution has a vim-full or vim-enhanced version, and I tested what I posted here against the Windows gvim
    ojblass : Crazy Kudos I am going to wait to see if any golf answer like four key strokes and your done win out. I wonder what assumptions I should be allowed to make about the vim bulid itself to still be considered portable.
    George V. Reilly : You still have to have python2X.dll somewhere on your computer for this to work. Python itself is not embedded in Vim.
  • Here is a command in Vim language. So you don't have to compile Vim with +python support.

    function! s:transpose()
        let maxcol = 0
        let lines = getline(1, line('$'))
    
        for line in lines
            let len = len(line)
            if len > maxcol 
                let maxcol = len
            endif
        endfor
    
        let newlines = []
        for col in range(0, maxcol - 1)
            let newline = ''
            for line in lines
                let line_with_extra_spaces = printf('%-'.maxcol.'s', line)
                let newline .= line_with_extra_spaces[col]
            endfor
            call add(newlines, newline)
        endfor
    
        1,$"_d
        call setline(1, newlines)
    endfunction
    
    command! TransposeBuffer call s:transpose()
    

    Put this in newly created .vim file inside vim/plugin dir or put this to your [._]vimrc.
    Execute :TransposeBuffer to transpose current buffer

    ojblass : Pure vim gets you the nod. Thank you so much!
  • If scripts don't do it for you, you could record the actions to a register (the carriage returns are added for readability):

    qa
    1G0
    xGo<Esc>p
    1G0j
    xGp
    q
    

    This will give you a macro that you could run against the example above, or any 2-line strings of the same length. You only need to know the length of the string so you can iterate the operation the correct number of time

    16@a
    

    A fairly basic solution, but it works.

    ojblass : The input domain could be more than two lines with the same length.

0 comments:

Post a Comment

Note: Only a member of this blog may post a comment.