2013-02-10 2 views
6

Я пытаюсь чередовать три группы строк текста. Например идут отПереплетение строк vim

a 
a 
a 
b 
b 
b 
c 
c 
c 

Для

a 
b 
c 
a 
b 
c 
a 
b 
c 

Есть эффективный способ сделать это?

+0

Это реальная ситуация в мире или уменьшенный тестовый пример? – romainl

+0

Уменьшенный тестовый чехол. Есть три группы, которые должны быть чересстрочными, но их более 3-х предметов. Я мог бы изменить макрос, но я думал, что может быть лучший способ: g и move – jpiasetz

+0

Хмм, если все 'a' одинаковы, а 'b' одинаковы, а 'c' одинаковы ' d просто закажите первый 'abc' вручную (':/b/m.',':/c/m.') и дублировать полученный блок 3 раза (что довольно быстро), но ваши потребности в реальном мире, вероятно, более сложны. – romainl

ответ

0

Вот «Oneliner» (почти), но вы должны повторить это для каждой уникальной линии минус 1, в вашем примере 2 раза. Возможно, бесполезно, но я думаю, что это было хорошее упражнение, чтобы больше узнать о шаблонах в VIM. Он обрабатывает все виды строк, пока целая линия уникальна (например, mno и mnp - две уникальные строки).

Сначала убедитесь, что это (и сделать не уже / отображаются на что-нибудь, или что-нибудь еще в линии):

:set nowrapscan 

Затем карту, например, эти (должны быть рекурсивными, неnnoremap):
<C-R> и <CR> должны быть набраны буквально.
\v в шаблонах означает «очень магия», @! отрицательный взгляд вперед. \2 используйте то, что найдено во второй круглой скобке.

:nmap ,. "xy$/\v^<C-R>x$<CR>:/\v^(<C-R>x)@!(.*)$\n(\2)$/m-<CR>j,. 
:nmap ,, gg,. 

Затем сделайте ,, столько раз, сколько это занимает, в вашем примере 2 раза. Один для всех b s и один для всех c s.


EDIT: объяснение отображения. Я буду использовать пример в вопросе, как если бы он работал один раз с этим сопоставлением.
После одного запуска:

1. a 
2. b 
3. a 
4. b 
5. a 
6. b 
7. c 
8. c 
9. c 

Курсор затем на последней a (строка 5), при вводе ,,, это первый вернуться к первой линии, а затем запускает отображение для ,., и что отображение делает это:

"xy$    # yanks current line (line 1) to reg. "x" ("a") " 
/\v^<C-R>x$<CR> # finds next line matching reg. "x" ("a" at line 3) 
:/\v^(<C-R>x)@!(.*)$\n(\2)$/m-<CR> 
# finds next line that have a copy under it ("c" in line 7) and moves that line 
# to current line (to line 3, if no "-" #after "m" it's pasted after current line) 
# Parts in the pattern: 
- ^(<C-R>x)@!(.*)$ # matches next line that don't start with what's in reg. "x" 
- \n(\2)$   # ...and followed by newline and same line again ("c\nc") 
- m-<CR>   # inserts found line at current line (line 3) 
j    # down one line (to line 4, where second "a" now is) 
,.    # does all again (recursive), this time finding "c" in line 8 
... 
,.    # gives error since there are no more repeated lines, 
       # and the "looping" breaks. 
5

Где-то в глубине моих ~/.vim файлов У меня есть команда :Interleave (добавлено ниже). Без аргументов :Interleave будет просто чередовать как обычно. С двумя аргументами, как он будет указывать, сколько из них должно быть сгруппировано. например :Interleave 2 1 займет 2 строки сверху, а затем чередуется с 1 рядом со дном.

Теперь, чтобы решить вашу проблему

:1,/c/-1Interleave 
:Interleave 2 1 
  • 1,/c/-1 диапазон, начиная с первой строки и заканчивая 1 строку выше первой линии, соответствующей письмо c.
  • :1,/c/-1Interleave в основном чередовать группы a-х и b 's
  • :Interleave 2 1 диапазон весь файл на этот раз.
  • :Interleave 2 1 interleave группа смешанных a и b с группой c s. Со смесями от 2 до 1.

Код :Interleave приведен ниже.

command! -bar -nargs=* -range=% Interleave :<line1>,<line2>call Interleave(<f-args>) 
fun! Interleave(...) range 
    if a:0 == 0 
    let x = 1 
    let y = 1 
    elseif a:0 == 1 
    let x = a:1 
    let y = a:1 
    elseif a:0 == 2 
    let x = a:1 
    let y = a:2 
    elseif a:0 > 2 
    echohl WarningMsg 
    echo "Argument Error: can have at most 2 arguments" 
    echohl None 
    return 
    endif 
    let i = a:firstline + x - 1 
    let total = a:lastline - a:firstline + 1 
    let j = total/(x + y) * x + a:firstline 
    while j < a:lastline 
    let range = y > 1 ? j . ',' . (j+y) : j 
    silent exe range . 'move ' . i 
    let i += y + x 
    let j += y 
    endwhile 
endfun 
+0

Интересный [сшивка] (http://vi.stackexchange.com/a/4576/2978)? ;) –

1

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

  • A) Это предполагает, что существует какая-то уникальный характер (или произвольный характер строка) не присутствует ни в одном из направлений - Я полагаю, @ ниже.
  • B) Он предполагает, что вы не хотите, чтобы пробелы в левом или заднем плане находились в любом из разделов a, b или c.
  • C) Предполагается, что вы можете легко определить максимальную длину строки , а затем колодки все линии, чтобы быть, что длина (например, возможно с помощью%! В AWK или т.п., используя Printf)

    1. Pad все линии с пробелами до одной и той же максимальной длины.
    2. Визуальный Выберите только разделы a и b, затем %s/$/@
    3. Скопируйте копию и пройдите мимо раздела b, предшествующего разделу c.
    4. Заблокируйте копию и вставьте раздел, предшествующий разделу bc.
    5. %s/@/\r
    6. %s/^ *//g
    7. %s/ *$//g
    8. удалите строки влево, где а и Ь секции были.
0

Если у вас есть xclip вы можете вырезать линии и использовать paste чередовать их:

  1. Визуальная выбрать один набор линий
  2. Тип "+d, чтобы сократить их в буфер обмена
  3. Визуальный выбор другого набора линий
  4. Тип !paste -d '\n' /dev/stdin <(xclip -o -selection clipboard)