Подтвердить что ты не робот

Сортировка слов (не строк) в VIM

Встроенная команда VIM :sort сортирует строки текста. Я хочу сортировать слова в одной строке, например. преобразовать линию

b a d c e f

к

a b c d e f

В настоящее время я выполняю это, выбирая строку, а затем используя :!tr ' ' '\n' | sort | tr '\n' ' ', но я уверен, что там лучше, проще и быстрее. Есть?

Обратите внимание, что я использую bash, поэтому, если для этого есть более короткая и элегантная команда bash, она также прекрасна.

EDIT: Мое использование - это то, что у меня есть строка, которая говорит SOME_VARIABLE="one two three four etc", и я хочу, чтобы слова в этой переменной были отсортированы, т.е. я хочу иметь SOME_VARIABLE="etc four one three two".

Конечный результат предпочтительно должен отображаться с помощью сочетания клавиш, так как это то, что мне часто нужно.

4b9b3361

Ответ 1

Используя отличные идеи из ваших ответов, особенно ответ Al, я в итоге придумал следующее:

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

Это отображает кнопку F2 в режиме visual, чтобы удалить выделенный текст, разбить, отсортировать и присоединиться к нему, а затем снова вставить его. Когда выбор охватывает несколько строк, это сортирует слова во всех из них и выводит одну отсортированную строку, которую я могу быстро исправить, используя gqq.

Я буду рад услышать предложения о том, как это можно улучшить.

Большое спасибо, я многому научился:)

EDIT: изменено '<C-R>"' на getreg('"') для обработки текста с помощью char ' в нем.

Ответ 2

В чистом 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

Ответ 3

Здесь эквивалент в чистом 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

и т.д.

Ответ 4

:!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, сортирует данный список, печатает - печатает его.

Ответ 5

Возможно, вы предпочитаете Python:

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

Визуальный текст выбора и выполните эту строку.

Ответ 6

My Плагин AdvancedSorters теперь имеет команду :SortWORDs, которая делает это (среди других команд, связанных с сортировкой).