VIM按照列合并行

2021-12-22  本文已影响0人  SpaceCat

之所以写这篇单独记下这个问题,是因为我觉得这篇里面读取全部文本行并逐行处理的技巧,是VIM高手和一般用户的分水岭。也就是说,这篇是一条vim的金线。

1、场景说明

这里要处理的文本有很多行,每行中有两列,列之间用\t分隔如下:

asdf    1
asdf    1
qwer    3
qwer    3
qwer    3
qwer    3
qwer    3
asdf    1
asdf    1
qwer    3
qwer    3
qwer    3
qwer    3

我们想将第一列相同的行合并到一起,达到如下效果:

asdf    1, 1, 1, 1
qwer    3, 3, 3, 3, 3, 3, 3, 3, 3

2、解决方法

这里通过自定义一个vim命令来解决。在自定义命令中,调用了一个自定义的函数,如下:

" define a command to merge lines according to the first column
" every line has just two column split by \t
function! MergeLinesAsFirstColumn()
    let dict = {}
    let reslist = []
    let @u = ''
    g/$/let ln=getline(".") | let tmplist = split(ln, "\t") | if !has_key(dict, tmplist[0]) | let dict[tmplist[0]] = tmplist[1] | else | let dict[tmplist[0]] = dict[tmplist[0]] . ', ' . tmplist[1] | endif
    for [k,v] in items(dict) | call add(reslist, k . "\t" . v) | endfor
    let @u = join(reslist, "\n")
    normal! ggdG
    normal! 0"up
    echo "Merge lines finished!"
    return ''
endfunction
command MergeLinesAsFirstColumn exec MergeLinesAsFirstColumn()

将前面的行放到vimrc配置文件中,执行命令source $MYVIMRC让配置生效,生效之后,在vim命令行执行:MergeLinesAsFirstColumn,就可以实现前面效果的行合并。

3、分解和优化

前面这个版本是我在解决问题的时候,参照一个别的问题的脚本改出来的,可读性比较差。实际上,这里涉及的读取全部文本行并处理的技巧,适用的场景非常广泛。所以,这里对前面的版本进行了分解和优化,主要是提高了代码的可读性。如下:

" define a command to merge lines according to the first column
" every line has just two column split by \t
function! MergeLinesAsFirstColumn2()
    " read all lines into a list
    let allLines = []
    g/$/let line=getline(".") | call add(allLines, line)
    
    " Merging as the first column
    let dict = {}
    for l in allLines
        let tmpList = split(l, "\t")
        if !has_key(dict, tmpList[0])
            let dict[tmpList[0]] = tmpList[1]
        else
            let dict[tmpList[0]] = dict[tmpList[0]] . ', ' . tmpList[1]
        endif
    endfor

    " join the merge result into a result list, then to a register u
    let resList = []
    for [k,v] in items(dict)
        call add(resList, k . "\t" . v)
    endfor
    let @u = join(resList, "\n")
    normal! ggdG
    normal! 0"up
    "echo "Merge lines finished!"
    return ''
endfunction
command MergeLinesAsFirstColumn2 exec MergeLinesAsFirstColumn2()

将前面的行放到vimrc配置文件中,执行命令source $MYVIMRC让配置生效,生效之后,在vim命令行执行:MergeLinesAsFirstColumn2,就可以实现前面效果的行合并。

上一篇下一篇

猜你喜欢

热点阅读