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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1327978/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 21:09:19  来源:igfitidea点击:

Sorting words (not lines) in VIM

bashvim

提问by drrlvn

The built-in VIM :sortcommand sorts lines of text. I want to sort words in a single line, e.g. transform the line

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

b a d c e f

to

a b c d e f

Currently I accomplish this by selecting the line and then using :!tr ' ' '\n' | sort | tr '\n' ' ', but I'm sure there's a better, simpler, quicker way. Is there?

目前,我通过选择该行然后使用 来完成此操作:!tr ' ' '\n' | sort | tr '\n' ' ',但我确信有更好、更简单、更快捷的方法。在那儿?

Note that I use bash so if there's a shorter and more elegant bash command for doing this it's also fine.

请注意,我使用 bash,因此如果有一个更短、更优雅的 bash 命令来执行此操作,也可以。

EDIT:My use-case is that I have a line that says SOME_VARIABLE="one two three four etc"and I want the words in that variable to be sorted, i.e. I want to have SOME_VARIABLE="etc four one three two".

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

The end result should preferably be mappable to a shortcut key as this is something I find myself needing quite often.

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

采纳答案by drrlvn

Using great ideas from your answers, especially Al's answer, I eventually came up with the following:

使用您的答案中的好主意,尤其是 Al 的答案,我最终想出了以下内容:

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

This maps the F2button in visualmode to delete the selected text, split, sort and join it and then re-insert it. When the selection spans multiple lines this will sort the words in all of them and output one sorted line, which I can quickly fix using gqq.

这将F2按钮映射到visual模式以删除所选文本、拆分、排序和连接它,然后重新插入它。When the selection spans multiple lines this will sort the words in all of them and output one sorted line, which I can quickly fix using gqq.

I'll be glad to hear suggestions on how this can be further improved.

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

Many thanks, I've learned a lot :)

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

EDIT: Changed '<C-R>"'to getreg('"')to handle text with the char 'in it.

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

回答by DrAl

In pure vim, you could do this:

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

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

Edit

编辑

To do this so that it works over a range that is less than one line is a little more complicated (this allows either sorting multiple lines individually or sorting part of one line, depending on the visual selection):

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

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

回答by rampion

Here's the equivalent in pure vimscript:

这是纯 vimscript 中的等效项:

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

It's no shorter or simpler, but if this is something you do often, you can run it across a range of lines:

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

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

Or make a command

或者发出命令

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

Which you can use with

您可以使用

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

etc etc

等等等等

回答by rampion

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

Not sure if it requires explanation, but if yes:

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

perl -ne ''

runs whatever is within '' for every line in input - putting the line in default variable $_.

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

$,=" ";

Sets list output separator to space. For example:

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

=> 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

Pretty simple.

很简单。

print sort split /\s+/

Is shortened version of:

是缩短版:

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

($_ at the end is default variable).

(末尾的 $_ 是默认变量)。

split - splits $_ to array using given regexp, sort sorts given list, print - prints it.

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

回答by iElectric

Maybe you preffer Python:

也许你更喜欢 Python:

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

Visual select text, and execute this line.

视觉选择文本,并执行此行。

回答by Ingo Karkat

My AdvancedSorters pluginnow has a :SortWORDscommand that does this (among other sorting-related commands).

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