内置的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} }。
最终结果应该最好是可以映射到快捷键,因为这是我经常需要的东西。
答案 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
命令执行此操作(以及其他与排序相关的命令)。