How to transpose the contents of lines and columns in a file in Vim?

前端 未结 6 639
既然无缘
既然无缘 2021-02-02 16:49

I know I can use Awk, but I am on a Windows box, and 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 to have s

相关标签:
6条回答
  • 2021-02-02 17:34

    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

    0 讨论(0)
  • 2021-02-02 17:37

    I've developed a vim plugin to do it. You can find it here. Run :Transpose to transpose the whole file.

    0 讨论(0)
  • 2021-02-02 17:38

    The following function performs the required editing operations to “transpose“ the contents of the current buffer, regardless of the number of lines in it.

    fu!T()
    let[m,n,@s]=[0,line('$'),"lDG:pu\r``j@s"]
    g/^/let m=max([m,col('$')])
    exe'%norm!'.m."A \e".m.'|D'
    sil1norm!@s
    exe'%norm!'.n.'gJ'
    endf
    

    For the sake of “golfing”, here is its one-line version:

    let[m,n,@s]=[0,line('$'),"lDG:pu\r``j@s"]|exe'g/^/let m=max([m,col("$")])'|exe'%norm!'.m."A \e".m.'|D'|exe'sil1norm!@s'|exe'%norm!'.n.'gJ'
    
    0 讨论(0)
  • 2021-02-02 17:43

    Charles Duffy's code could be shortened/improved using izip_longest instead of izip:

    function! Rotate()
        :py import vim, itertools
        :py vim.current.buffer[:] = [''.join(c) for c in itertools.izip_longest(*vim.current.buffer, fillvalue=" ")]
    endfunction
    
    0 讨论(0)
  • 2021-02-02 17:45

    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.

    0 讨论(0)
  • 2021-02-02 17:49

    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
    
    0 讨论(0)
提交回复
热议问题