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
Sorting words (not lines) in VIM
提问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执行此操作的命令(以及其他与排序相关的命令)。

