是否可以在vim中对一组行进行排序?

时间:2017-10-10 06:47:40

标签: sorting vim

据我所知vim:sort方法将对每一行进行排序。我有一些包含3行的代码。我该怎么办呢?请忽略糟糕的代码,这是一个遗留的应用程序:'(

我想根据案例'AF'排序,但忽略(分组)国家和分界线

case 'AF':
  country = 'Afghanistan';
  break;,
case 'AL':
  country = 'Albania';
  break;,
case 'DZ':
  country = 'Algeria';
  break;,
case 'AS':
  country = 'American Samoa';
  break;,
case 'AD':
  country = 'Andorra';
  break;,
case 'AO':
  country = 'Angola';
  break;,
case 'AI':
  country = 'Anguilla';
  break;,
case 'AQ':
  country = 'Antarctica';
  break;,
case 'AG':
  country = 'Antigua And Barbuda';
  break;,
case 'AR':
  country = 'Argentina';
  break;,
case 'AM':
  country = 'Armenia';
  break;,
case 'AW':
  country = 'Aruba';
  break;,
case 'AU':
  country = 'Australia';
  break;,
case 'AT':
  country = 'Austria';
  break;,
case 'AZ':
  country = 'Azerbaijan';
  break;,
case 'BS':
  country = 'Bahamas';
  break;,
case 'BH':
  country = 'Bahrain';
  break;,
case 'BD':
  country = 'Bangladesh';
  break;,
case 'BB':
  country = 'Barbados';
  break;,
case 'BY':
  country = 'Belarus';
  break;

4 个答案:

答案 0 :(得分:5)

@Halst建议的解决方案的流行语兼容版本:

  • 标记线
  • 将他们加入一个不会出现在代码中的字符:

    :'<,'>s/[:;]\zs\n/@/
    
  • 再次标记

  • 对它们进行排序:

    :'<,'>sort
    
  • 最后一次标记行

  • 将它们分开到@

    :'<,'>s/@/\r/g
    

您需要手动修复上一个字词。无需indentsort或任何其他外部程序。

如果将相关代码移动到废料缓冲区并在那里重新格式化,也可以避免标记行。

答案 1 :(得分:5)

我的AdvancedSorters plugin实现@Halst和@SatoKatsura建议的算法(加入,排序,然后取消加入)作为一个简单的自定义命令:

:SortRangesByHeader /^case/

该插件实现了各种其他排序方法,例如:通过折叠,范围等

答案 2 :(得分:4)

执行此操作的一种方法是将语句折叠为一行,如下所示:

case 'AG': country = 'Antigua And Barbuda'; break;

通过视觉选择并用空格替换换行符+缩进:

:'<,'>s/\n  / /g

然后对选择进行排序:

:'<,'>!sort

然后通过一些漂亮的打印机运行代码区域,例如,GNU indent

https://www.gnu.org/software/indent/manual/indent.html

这是采用机器格式代码的一个优点 - 您可以运行一个混乱的转换(例如正则表达式),然后自动修复它。

答案 3 :(得分:1)

我为此:SortGroup

创建了一个命令
" :[range]SortGroup[!] [n|f|o|b|x] /{pattern}/
" e.g. :SortGroup /^header/
" e.g. :SortGroup n /^header/
" See :h :sort for details

这意味着您可以:SortGroup /case/

实施如下:

function! s:sort_by_header(bang, pat) range
  let pat = a:pat
  let opts = ""
  if pat =~ '^\s*[nfxbo]\s'
    let opts = matchstr(pat, '^\s*\zs[nfxbo]')
    let pat = matchstr(pat, '^\s*[nfxbo]\s*\zs.*')
  endif
  let pat = substitute(pat, '^\s*', '', '')
  let pat = substitute(pat, '\s*$', '', '')
  let sep = '/'
  if len(pat) > 0 && pat[0] == matchstr(pat, '.$') && pat[0] =~ '\W'
    let [sep, pat] = [pat[0], pat[1:-2]]
  endif
  if pat == ''
    let pat = @/
  endif

  let ranges = []
  execute a:firstline . ',' . a:lastline . 'g' . sep . pat . sep . 'call add(ranges, line("."))'

  let converters = {
        \ 'n': {s-> str2nr(matchstr(s, '-\?\d\+.*'))},
        \ 'x': {s-> str2nr(matchstr(s, '-\?\%(0[xX]\)\?\x\+.*'), 16)},
        \ 'o': {s-> str2nr(matchstr(s, '-\?\%(0\)\?\x\+.*'), 8)},
        \ 'b': {s-> str2nr(matchstr(s, '-\?\%(0[bB]\)\?\x\+.*'), 2)},
        \ 'f': {s-> str2float(matchstr(s, '-\?\d\+.*'))},
        \ }
  let arr = []
  for i in range(len(ranges))
    let end = max([get(ranges, i+1, a:lastline+1) - 1, ranges[i]])
    let line = getline(ranges[i])
    let d = {}
    let d.key = call(get(converters, opts, {s->s}), [strpart(line, match(line, pat))])
    let d.group = getline(ranges[i], end)
    call add(arr, d)
  endfor
  call sort(arr, {a,b -> a.key == b.key ? 0 : (a.key < b.key ? -1 : 1)})
  if a:bang
    call reverse(arr)
  endif
  let lines = []
  call map(arr, 'extend(lines, v:val.group)')
  let start = max([a:firstline, get(ranges, 0, 0)])
  call setline(start, lines)
  call setpos("'[", start)
  call setpos("']", start+len(lines)-1)
endfunction
command! -range=% -bang -nargs=+ SortGroup <line1>,<line2>call <SID>sort_by_header(<bang>0, <q-args>)

注意:由于使用了lambda,因此需要Vim 8 +