Як змінити порядок рядків?


24

Як я можу змінити порядок рядків, щоб перший рядок з’явився в кінці, а останній з'явився першим? (Можуть бути всі рядки в буфері, діапазоні адрес або вибору лінійного візуального режиму.)

Я хотів би перетворитись

rat
ox
tiger
⋮
dog
pig

в

pig
dog
⋮
tiger
ox
rat

не вдаючись до зовнішньої команди, такої як tac.


Будь-які пропозиції щодо кращих тегів у цьому питанні?
200_успіх

1
можливо новий тег "pure-vi" чи подібний тег? Я бачив кілька запитань, які отримали б користь від тегу, який би вказував на бажання не використовувати жодних зовнішніх інструментів. Чи варто запитати про це на Meta?
Джон О'М.

1
@Carpetsmoker (і будь-хто інший, хто зацікавлений у цьому), тег-питання тепер знаходиться на meta meta.vi.stackexchange.com/questions/1229/…
Джон О'М.

Відповіді:


29

Тут діє глобальна сила:

:g/^/exe "normal ddggP"

Або, простіше (спасибі @tommcdo)

:g/^/move 0

Перший буде відповідати кожному рядку та кожному рядку, видалити його та вставити у верхню частину файлу. Під час переміщення по файлу він перевертає текст.

Другий аналогічно відповідає кожному рядку і переміщує його у верхню частину файлу.

Примітка. Обидва ці роботи працюють у всьому файлі і не застосовуватимуться правильно для реверсування підмножини рядків. Дивіться відповідь Інго Каркат щодо рішення, яке працює в межах діапазону.

Опис:

gглобальна команда
/^/відповідає будь-якому рядку, який має початок (тобто всі рядки)
exeвиконує наступний рядок,
"normalвиконує команди звичайного режиму,
ddвидаліть рядок,
ggперемістіться до верхньої частини
Pвставки файлу вище поточного положення

move 0 переміщує поточний рядок нижче рядка 0 (що ставить його в позицію 1 або перший рядок файлу)


6
Замість :normalкоманди ми можемо використовувати команду Ex :move 0, яка переміщує рядок до початку буфера.
tommcdo

1
Також :executeнеобхідний лише тоді, коли команду потрібно будувати динамічно, наприклад :execute 'normal' g:user_command.
tommcdo

@tommcdo гарні бали! Я звик використовувати, :executeтому що я часто закінчую додавання інших Ex-команд після існуючих пізніше, і мені зручніше вже мати :exeтам, ніж потрібно повертатись і вставляти його пізніше. На жаль, ця звичка просочилася до цієї відповіді там, де вона не так сильно застосовується.
Джон О'М.

1
Більше пояснення щодо мого використання :execute: оскільки він займає рядок, він дає чітке розмежування того, де закінчуються команди в звичайному режимі, хоча я не будую рядок, мені легше знайти збалансовані лапки, ніж шукати <esc>або що б не було припинено. Знову ж таки, це особисті переваги та звичка. :-)
Джон О'М.

3
Це буде працювати для діапазону btw: :9,11g/^/move 8... Останнє число повинно бути початком діапазону мінус 1 (адаптовано з відповіді Інго).
Мартін Турной

13

Цей однолінійний (для вашого ~/.vimrc) визначає :Reverseкоманду; Ви також можете використовувати :globalчастину безпосередньо, але синтаксис :move(який ітеративно зміщує рядки до початку діапазону, тим самим перетворюючи його), запам'ятати нелегко:

:command! -bar -range=% Reverse <line1>,<line2>global/^/m<line1>-1

1
Як FYI для читачів, <line1>& & <line2>зобов'язані зробити цю роботу в діапазоні, тобто: :7,9Reverse(вони є особливостями command, ні globalабо move). Простіше :command! -bar -range=% Reverse :global/^/m 0буде також працювати, але лише для всього буфера ...
Мартін Турной

6

Чистий Вім:

:g/^/m0

Пояснення:

Згідно з цим :help multi-repeat, :gі його двоюрідний брат :vпрацює у двох проходах.

Перший пропуск :gпозначає кожен рядок, який відповідає {pattern}, а другий пропуск (мабуть, виконується починаючи з початку файлу і закінчуючи до кінця) виконує [cmd]. Вищеописане використання :gпереваг використовує замовлення, в якому обробляються рядки (що, мабуть, нормально, хоча, ймовірно, технічно не гарантується).

Він працює, спочатку позначаючи кожен рядок, потім переміщуючи перший позначений рядок у верхню частину файлу, потім переміщуючи другий у верхню частину файлу (вище рядка, переміщеного раніше), потім третій позначений рядок (знову вище перенесеного раніше рядок) і так далі, поки останній рядок у файлі не буде переміщений у верхню частину, фактично перевернувши файл.

Зауважте, що якби :gоброблені рядки були в будь-якому порядку, відмінному від верху до низу, ця команда не працюватиме.

Джерело: Зворотно всі лінії та потужність g у vim wikia.

Кілька прикладів із використанням зовнішніх команд:

  • tac(частина ядерних програм GNU - catзворотна):

    :%!tac                                                                                                                                                                                                                                                              
    
  • tail на BSD / OSX (не сумісний з POSIX):

    :%!tail -r
    

    -r Опція -r призводить до відображення введення у зворотному порядку за рядком.

    Перевірте: man tarдля детальної інформації.

Більше ідей див:


2
Хіба це не :g/^/m0те саме :g/^/move 0, що відповідь Джона?
муру

@muru Я думаю, що так, але це коротше (відповідно до vim wikia), і я додав різні пояснення з кількома додатковими прикладами використання командних рядків.
kenorb

Так, я підтримав через інші команди (я також прийшов на посаду tac). Але я підозрюю, що скоромовка була внаслідок повторення відповіді.
муру

Я знаю, що tacце згадувалося в ОП, але всі інші подібні питання все одно будуть дублювати це питання, тому добре згадати це ще раз. Джон взяв цей cmd з коментаря @tommcdo, я його взяв спочатку від DerMike , але, думаю, він взяв його просто з wikia, тому я надав кредити vim wikia, тому це не зовсім повторюється, оскільки пояснення зовсім інше.
kenorb

Це додає більшої цінності, оскільки це набагато коротша версія з правильним поясненням, і я також зараховую правильні джерела. Використання команд оболонки дуже просте та зручне. Якщо люди не згодні, вони можуть просто проголосувати, нічого не робити.
kenorb

6

У дусі функціонального VimL:

:call setline(1, reverse(getline(1, line('$'))))
  • getline(1, line('$'))повертає список усіх рядків у буфері. '$'є спеціальним аргументом, для line()якого вказується останній рядок у буфері.
  • reverse(...)повертає список вводу на місце. Потрібно використовувати, reverse(copy(...))якщо список вводу не слід змінювати.
  • setline(1, ...)замінює вказаний рядок другим аргументом. Коли другим аргументом є список, однакова кількість рядків, що й довжина списку, замінюється змістом списку.

Якщо вам подобається, ви також можете визначити команду, яка займає діапазон ( %весь буфер за замовчуванням )

:command! -bar -range=% Reverse call setline(<line1>, reverse(getline(<line1>, <line2>)))

1
Мені подобається ця відповідь. Він також не виділяє речі (якщо hlsearchце ввімкнено), як :g/команду з інших відповідей ... Хоча ефективність, можливо, гірша? Так як він getline(1, line('$'))отримує весь буфер в пам'яті. reverse()начебто, на місці, тож пам’яті, як такому, потрібно брати дуже мало…
Мартін Турной

3

Відповідно до документації Vim usr_12.txt - Розумні хитрощі

12.4 Зворотний порядок ліній

:globalКоманда може бути об'єднана з :moveкомандою , щоб перемістити всі рядки до першого рядка, в результаті чого в зворотному файл. Команда така:

:global/^/m 0

Скорочено:

:g/^/m 0

^Регулярний вираз відповідає початку рядка (навіть якщо рядок порожня). :moveКоманда переміщує збігається рядок після міфічної нульової лінії, так що струм узгодження лінія стає першим рядком файлу. Оскільки :globalкоманду не плутає зміна нумерації рядків, :globalпереходить до узгодження всіх решти файлу і ставить кожну як першу.

Це також працює на ряді ліній. Спочатку перейдіть до першого рядка та позначте його mt. Потім перемістіть курсор до останнього рядка в діапазоні та введіть:

:'t+1,.g/^/m 't

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.