Як повернути кожні 4 рядки?


13

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

Моє запитання: я знаю, як повернути ВСІ рядки у файлі (: g / ^ / m0 серед інших способів), але чи є спосіб повернути кожні 4 рядки у файл, щоб

line1
line2
line3
line4
line5
line6
line7
line8
...

стає

line4
line3
line2
line1
line8
line7
line6
line5
...

Можна припустити, що в таких файлах завжди буде точно кратне 4 рядки.


2
Про ваш "ps": якщо ви вставляєте 4 пробіли перед рядком, це інтерпретується як код (ви можете вибрати текст і скористатися кнопками формату вгорі). Більш детальну інформацію можна знайти на значку допиту вгорі .
mMontu

Відповіді:


15

Для цього можна використовувати команду, :Reverseпояснену у Vim Wiki (ви можете включити її у свій, .vimrcщоб зробити її постійною):

command! -bar -range=% Reverse <line1>,<line2>g/^/m<line1>-1|nohl

Потім ви можете записати макрос для запуску команди в кожні чотири рядки:

qmV3j:Reverse<cr>4jq
1000@m

Пояснення:

  • qm: 'q' у звичайному режимі починає (і зупиняє) запис макросу в даний регістр (реєструйте 'm', в цьому випадку, але це може бути будь-яка інша літера)
  • V: перейдіть у візуальний режим і виберіть поточний рядок
  • 3j: розширити візуальний вибір до наступних 3 рядків
  • :Reverse<cr>: запустіть команду "Зворотний" у вибраних рядках ( <cr>тут розшифровується enterключ)
  • 4j: перехід до наступних незмінних рядків
  • q: припиняє запис макросу
  • 1000@m: запустіть макрос, записаний при реєстрації 'm' 1000 разів (ви можете збільшити це число, якщо ваш файл перевищує 4000 рядків)

Редагувати:

Як згадувалося в коментарях, ви можете використовувати рекурсивний макрос, а не використовувати кількість:

qmV3j:Reverse<cr>4jq
qM@mq
@m
  • qM: якщо реєстр, вказаний для qверхнього регістру, макрос додається до реєстру (що також корисно, коли ви розумієте, коли пропустили останні кроки складного макросу)
  • @m: запустити макрос на регістр m
  • q: припиніть додавати макрос

Незважаючи на те, що він створений як макрос, ви можете створити команду для цього, якщо це звичайне завдання у вашому робочому процесі:

function! Reverse4()
   let reg_m = @m
   let @m = '<c-r><c-r>m'
   normal! @m
   let @m = reg_m
endfunction
command! Reverse4 call Reverse4()
  • function! Reverse4()/ endfunction: визначає нову функцію
  • let reg_m = @m: зберігає поточний вміст регістра m
  • let @m = "<c-r><c-r>m": вставити макрос в реєстр m- зауважте, що <c-r>це позначення vim для Ctrl+ rі що ви повинні вводити це, а не копіювати / вставляти, так що ваш рядок буде подібний let @m = 'V3j:Reverse^M4j@m'і буде містити спеціальний символ (^ M)
  • normal! @m: звичайна команда запустить свій аргумент так, як він був введений у звичайному режимі, тому він запустить рекурсивний макрос
  • let @m = reg_m: відновлює вміст реєстру m, тому вам не потрібно пам’ятати, що цей регістр використовується у цій функції та уникайте його використання

  • command! Reverse4 call Reverse4(): створити нову команду для цієї функції

Залежно від ваших потреб, ви можете їх покращити, наприклад: передайте аргумент команді та функції, щоб він працював для будь-якої кількості рядків замість того, щоб закріплюватися на групи з 4 рядків.


Замість 1000@qхака, ви можете також використовувати рекурсивний макрос: qmqqm ... @mq@m.
Doorknob

Коли я спробував запустити "qmV3j: Reverse <cr> 4jq", він сказав "E492: Не команда редактора". Я мушу щось робити не так. Я, до речі, використовую - і тільки коли-небудь використовував - GVIM. Я мав би це згадати в першу чергу.
capawasiereisawelba

Ах, неважливо. Я зрозумів це - я не повинен вводити ":" перед частиною "qmV3j: Зворотний <cr> 4jq". Це спрацювало! Дуже дякую, mMontu. Якщо я можу запитати - як я включаю команду ": Зворотний" у свій .vimrc?
ablewasiereisawelba

3
@ablewasiereisawelba Щоб команда була доступною постійно, просто напишіть рядок command! -bar -range=% Reverse <line1>,<line2>g/^/m<line1>-1|nohlдесь у вашому vimrc.
saginaw

@saginaw О, я не розумів, що це було просто. Дякую.
ablewasiereisawelba

9

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

(У цьому випадку я буду використовувати рекурсивний макрос, але ви можете просто записати нерекурсивний і відтворити його кілька разів молотком @@або за допомогою підрахунку.)

ggqqqqqddjjpkddkkPjddpjj@qq@q

Зломаний

  1. gg: Перехід до початку файлу.
  2. qqq: Очистити реєстр q. Ми побачимо, чому це потрібно на кроці 5.
  3. qq: Почніть записувати макрос для реєстрації q
  4. ddjjpkddkkPjddpjj: Серія операцій, яка впорядковує перші чотири рядки, просто видаляючи та вставляючи їх вручну. (Це може здатися складним на перший погляд, але не обманюйте себе Це дуже просту річ , що ви б дізналися в перші 5 хвилин або так. vimtutor: j, k, dd, p, P)
  5. @q: Викличте макрос! На даний момент реєстр qнічого не містить (тому що ми його очистили на кроці 2), тому нічого не відбудеться.
  6. q: Зупиніть запис макросу.
  7. @q: Повторіть рекурсивний макрос стільки разів, скільки потрібно.

Примітка. Наведене вище не призведе до бажаних результатів, якщо файл містить ряд рядків, які не точно розділяються на чотири. Щоб рано зупинити макрос, якщо не залишилося чотирьох рядків, нам потрібно виконати команду Vim у звичайному режимі, яка вийде з ладу, перш ніж розпочати застосування змін на кроці 4. Це можна зробити, намагаючись рухатись вниз лінію тричі (а потім резервну копію), перш ніж ми почнемо рухати лінії навколо:jjj3k

Таким чином:

ggqqqqqjjj3kddjjpkddkkPjddpjj@qq@q

Чому ви чітко очищаєте регістр q? Якщо ви просто записуєте на нього, все, що там було, все одно буде перезаписано ....
Wildcard

4
@Wildcard Оскільки рекурсивний макрос, коли ви вперше викликаєте вміст реєстру q, він повинен бути порожнім, інакше він зіпсує ваші видання.
saginaw

Дуже хороша. Я спробував це в інтерактивному режимі, не намагаючись ввести точну послідовність вашої команди і завершився, використовуючи:qqqggqqjjjkddkkPjddjpkddkkPjjjj@qq@q
Wildcard

1
@ablewasiereisawelba where I can just use the one-line custom command each time I need to do this- зауважте, що вам не доведеться заново створювати макрос щоразу, коли вам потрібно його використовувати, оскільки це можливо зберегти як функцію / команду у вашому vimrc.
mMontu

1
@ablewasiereisawelba Я радий, що "Редагування" знайшлося корисним! Оскільки це був ваш перший пост тут, можливо, ви не знаєте, як працює сповіщення StackExchange: коли ви публікуєте коментар, автор відповідей / питань отримує повідомлення; інші особи отримають сповіщення лише у тому випадку, якщо ви включите @ <nick>. Таким чином, лише Річ отримував сповіщення про ваші останні повідомлення.
mMontu

7

Ви також можете це зробити за допомогою Exкоманди, яка використовується sedяк зовнішній фільтр:

:%!sed -n 'h;n;G;h;n;G;h;n;G;p'

Ця версія буде ігнорувати (видаляти) будь-які додаткові рядки, що перевищують кратне число 4. Щоб зберегти в останньому наборі менше 4 рядків (перевернутий), використовуйте:

:%!sed -n '$p;h;n;G;$p;h;n;G;$p;h;n;G;p'

%Тут означає «Кожну рядок в буфері.»

У !засобі командного «Виконайте наступну команду з заданими лініями в якості вхідних даних, і замінити зазначені рядки з висновком команди.» (Це називається фільтр; дуже зручно для таких речей, як сортування, наприклад, :%!sortсортуватиме всі рядки у вашому файлі; :2,8!sortбуде сортувати рядки 2-8 тощо).

sedє інструментом редактора потоків і знаходиться у всіх системах, схожих на Unix. Ключові поняття, sedякі тут використовуються, - це "простір шаблону" (який за замовчуванням просто містить кожен рядок вводу по черзі) та "утримувати пробіл" (саме там ви можете вставити додатковий текст, використовуючи sedдля збереження його під час обробки інших рядки введення).

-nє опцією для sedкоманди, щоб придушити свої типові дії друку простору шаблону (тому що в цьому випадку ми хочемо друкувати лише тоді, коли явно так сказамо.)

$pв sedкоманді означає "Якщо ви знаходитесь в останньому рядку введення sed', надрукуйте (пробіл шаблону)."

h означає "вставити поточний вміст" простору шаблону "у" простір утримування ", перезаписавши все, що там є".

n означає "замінити вміст" простору шаблону "на наступний рядок із введення."

G означає "додати до" простору шаблону ": новий рядок з подальшим вмістом" пробілу "."

У сукупності sedкоманда зберігає чотири рядки виводу, реверсує їх у міру їх зберігання, а потім роздруковує. Ці $pкоманди , додані в другій версії переконатися , що якщо останній рядок файлу досягається за винятком на кратному 4 лінії, лінії по - , як і раніше друкуються.


Для альтернативного інтерактивного підходу без використання будь-яких функцій Vim, а також без використання зовнішнього фільтра:

:4

перейти до четвертого рядка.

:.m -4 | +3m . | +2m . | +5

щоб змінити попередні чотири рядки (1-4) та залишити курсор у рядку 8.

.m -4переміщує поточний рядок безпосередньо після рядка чотирьох рядків назад (залишаючи курсор на переміщеній лінії).

+3m .переміщує лінію, що знаходиться на 3 рядки після поточної лінії, до одразу після поточного рядка, залишаючи курсор на переміщеній лінії. +2m .звичайно працює так само.

+5 розміщує курсор на п’ять рядків вниз від місця, де він знаходиться.

Повторіть за бажанням.

У Vim ви можете повторити всю цю команду @:, а потім повторити ще раз з @@. У POSIX viабо exвам потрібно буде вставити текст :.m -4 | +3m . | +2m . | +5 як рядок тексту, видаліть його з названим буфером (регістром), а потім виконайте цей іменований буфер (регістр).

Тож у exрежимі реверсуються рядки в інтерактивному режимі, використовуючи лише визначені POSIX функції та починаючи з 17 рядків тексту:

Entering Ex mode.  Type "visual" to go to Normal mode.
:0a     # Append following text after "line 0" (i.e. insert at start of file).
.m -4 | +3m . | +2m . | +5
.       # End text insertion
:d k    # Delete that line to register k
line1   # This is a printout of the current line
:4      # Move to line 4
line4
:@k     # Execute register k to reverse lines 1-4
line8
:@@     # Execute register k again
line12
:@@     # Execute register k again
line16
:@@     # Execute register k again
line17
:%p     # Print the whole buffer (just to see what was done)
line4
line3
line2
line1
line8
line7
line6
line5
line12
line11
line10
line9
line16
line15
line14
line13
line17
:wq     # Save and quit

Подальше читання:


Чи можете ви пояснити трохи більше свого рішення?
vappolinario

3
@vappolinario, я додав ще одне пояснення. Чи допомагає це? :)
Wildcard

Вау, дуже довга відповідь. :) Насправді у мене є sed, але я тільки що використовував його з одним простим сценарієм, який я десь знайшов - напевно, на цій дошці - це було вирішенням проблеми, яку я мав. Однак, коли я спробував запустити запропонований рядок, він говорить, що "sed" не розпізнається як внутрішня чи зовнішня команда, функціонуюча програма або пакетний файл. " Я не впевнений, чи потрібно мені мати папку в папці vim чи що.
ablewasiereisawelba

1
@ablewasiereisawelba, якщо ви працюєте у вікні Windows і не використовуєте Cygwin (або MobaXterm чи подібний), ви можете спробувати інший метод, який я дав: 4G:.m -4 | +3m . | +2m . | +5<Enter>@:потім @@повторюйте, поки ваш файл не буде повністю оброблений. Я рекомендую встановити MobaXterm. :)
Wildcard

@Wildcard Ну добре, я зараз перевіряю MobaXterm. :)
ablewasiereisawelba

7
:g/^/exe 'm .-' . substitute(line('.') % 4, '^0$', '4', '')

Звичайна англійська: для кожного рядка переміщуйте поточну лінію вгору lnum % 4, якщо тільки lnum % 4 == 0в цьому випадку не переміщуйте поточну лінію вгору 4.

Крім того, щоб повернути всі nрядки, замініть команду 4's у наведеній вище команді n.


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