在VIM中对单词(不是行)进行排序

时间:2009-08-25 12:30:16

标签: bash vim

内置的VIM :sort命令可对文本行进行排序。我想在一行中对单词进行排序,例如变换线

b a d c e f

a b c d e f

目前我通过选择该行然后使用:!tr ' ' '\n' | sort | tr '\n' ' '来实现此目的,但我确信这是一种更好,更简单,更快捷的方法。有吗?

请注意,我使用bash,所以如果有一个更短更优雅的bash命令来执行此操作,那也没关系。

编辑:我的用例是我有一行说SOME_VARIABLE="one two three four etc",我想要对该变量中的单词进行排序,即我希望{{1} }。

最终结果应该最好是可以映射到快捷键,因为这是我经常需要的东西。

6 个答案:

答案 0 :(得分:21)

在纯vim中,你可以这样做:

call setline('.', join(sort(split(getline('.'), ' ')), " "))

修改

要做到这一点,使它在小于一行的范围内工作有点复杂(这允许单独排序多行或排序一行的一部分,具体取决于视觉选择):

command! -nargs=0 -range SortWords call SortWords()
" Add a mapping, go to your string, then press vi",s
" vi" selects everything inside the quotation
" ,s calls the sorting algorithm
vmap ,s :SortWords<CR>
" Normal mode one: ,s to select the string and sort it
nmap ,s vi",s
function! SortWords()
    " Get the visual mark points
    let StartPosition = getpos("'<")
    let EndPosition = getpos("'>")

    if StartPosition[0] != EndPosition[0]
        echoerr "Range spans multiple buffers"
    elseif StartPosition[1] != EndPosition[1]
        " This is a multiple line range, probably easiest to work line wise

        " This could be made a lot more complicated and sort the whole
        " lot, but that would require thoughts on how many
        " words/characters on each line, so that can be an exercise for
        " the reader!
        for LineNum in range(StartPosition[1], EndPosition[1])
            call setline(LineNum, join(sort(split(getline('.'), ' ')), " "))
        endfor
    else
        " Single line range, sort words
        let CurrentLine = getline(StartPosition[1])

        " Split the line into the prefix, the selected bit and the suffix

        " The start bit
        if StartPosition[2] > 1
            let StartOfLine = CurrentLine[:StartPosition[2]-2]
        else
            let StartOfLine = ""
        endif
        " The end bit
        if EndPosition[2] < len(CurrentLine)
            let EndOfLine = CurrentLine[EndPosition[2]:]
        else
            let EndOfLine = ""
        endif
        " The middle bit
        let BitToSort = CurrentLine[StartPosition[2]-1:EndPosition[2]-1]

        " Move spaces at the start of the section to variable StartOfLine
        while BitToSort[0] == ' '
            let BitToSort = BitToSort[1:]
            let StartOfLine .= ' '
        endwhile
        " Move spaces at the end of the section to variable EndOfLine
        while BitToSort[len(BitToSort)-1] == ' '
            let BitToSort = BitToSort[:len(BitToSort)-2]
            let EndOfLine = ' ' . EndOfLine
        endwhile

        " Sort the middle bit
        let Sorted = join(sort(split(BitToSort, ' ')), ' ')
        " Reform the line
        let NewLine = StartOfLine . Sorted . EndOfLine
        " Write it out
        call setline(StartPosition[1], NewLine)
    endif
endfunction

答案 1 :(得分:14)

使用你的答案中的好主意,特别是Al的答案,我最终想出了以下内容:

:vnoremap <F2> d:execute 'normal i' . join(sort(split(getreg('"'))), ' ')<CR>

这会在visual模式下映射 F2 按钮以删除所选文本,拆分,排序和连接,然后重新插入。当选择跨越多行时,这将对所有行中的单词进行排序并输出一个排序的行,我可以使用gqq快速修复。

我很高兴听到有关如何进一步改进的建议。

非常感谢,我学到了很多东西:)。

编辑:将'<C-R>"'更改为getreg('"')以处理其中包含字符'的文字。

答案 2 :(得分:9)

这是纯vimscript中的等价物:

 :call setline('.',join(sort(split(getline('.'),' ')),' '))

这不是更短或更简单,但如果这是你经常做的事情,你可以在一系列行中运行它:

 :%call setline('.',join(sort(split(getline('.'),' ')),' '))

或者发出命令

 :command -nargs=0 -range SortLine <line1>,<line2>call setline('.',join(sort(split(getline('.'),' ')),' '))

您可以使用

:SortLine
:'<,'>SortLine
:%SortLine

等等

答案 3 :(得分:6)

:!perl -ne '$,=" ";print sort split /\s+/'

不确定是否需要解释,但如果是:

perl -ne ''

为输入中的每一行运行''内的任何内容 - 将该行放在默认变量$ _。

$,=" ";

将列表输出分隔符设置为空格。例如:

=> perl -e 'print 1,2,3'
123

=> perl -e '$,=" ";print 1,2,3'
1 2 3

=> perl -e '$,=", ";print 1,2,3'
1, 2, 3

非常简单。

print sort split /\s+/

缩短版本:

print( sort( split( /\s+/, $_ ) ) )

($ _结尾是默认变量)。

split - 使用给定的regexp将$ _拆分为数组,对给定列表进行排序,打印 - 打印它。

答案 4 :(得分:4)

也许您更喜欢Python:

!python -c "import sys; print ' '.join(sorted(sys.stdin.read().split()))"

视觉选择文本,然后执行此行。

答案 5 :(得分:1)

我的AdvancedSorters plugin现在有:SortWORDs命令执行此操作(以及其他与排序相关的命令)。