代码之家  ›  专栏  ›  技术社区  ›  Joe Woodward

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

  •  5
  • Joe Woodward  · 技术社区  · 7 年前

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

    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 回复  |  直到 7 年前
        1
  •  8
  •   Sato Katsura    7 年前

    @Halst建议的解决方案的符合流行语的版本:

    • 标记线条
    • :'<,'>s/[:;]\zs\n/@/
      
    • :'<,'>sort
      
    • 最后一次标记行

    • 在上拆分 @ :

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

    您需要手动修复最后一个术语。不需要 indent sort ,或任何其他外部程序。

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

        2
  •  6
  •   Ingo Karkat    7 年前

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

    :SortRangesByHeader /^case/
    

    该插件实现了各种其他排序方法,例如按折叠、范围等。

        3
  •  4
  •   Vladimir Keleshev    7 年前

    一种方法是将语句折叠成一行,如下所示:

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

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

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

    然后对选择进行排序:

    :'<,'>!sort
    

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

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

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

        4
  •  3
  •   Peter Rincker    4 年前

    我为此创建了一个命令 :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>)
    

    注:由于使用lambdas,这需要Vim 8+