交织线条vim

jpi*_*etz 6 vim

我试图交织三组文本行.例如来自

a
a
a
b
b
b
c
c
c
Run Code Online (Sandbox Code Playgroud)

a
b
c
a
b
c
a
b
c
Run Code Online (Sandbox Code Playgroud)

有没有一种有效的方法呢?

Pet*_*ker 6

在我的~/.vim文件深处的某处,我有一个:Interleave命令(附在下面).没有任何参数:Interleave只会正常交错.有两个参数,它将如何指定将多少组合在一起.例如,:Interleave 2 1从顶部开始排2行,然后从底部开始与1行交错.

现在来解决你的问题

:1,/c/-1Interleave
:Interleave 2 1
Run Code Online (Sandbox Code Playgroud)
  • 1,/c/-1范围从第一行开始,结束第一行,与第一行匹配c.
  • :1,/c/-1Interleave基本上交织了a's b' 和's'的组
  • :Interleave 2 1 这个范围是整个文件.
  • :Interleave 2 1将混合组abs 组交织在一起c.混合比为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
Run Code Online (Sandbox Code Playgroud)


244*_*4an 1

这是一个“oneliner”(几乎),但是您必须为每个唯一的行重做它-1,在您的示例中重做2次。也许没有用,但我认为这是一个很好的练习,可以进一步了解 VIM 中的模式。只要整条线是唯一的(例如mnomnp是两条唯一的线),它就可以处理所有类型的线。

首先确保这一点(并且没有映射/任何内容或行中的其他任何内容):

:set nowrapscan
Run Code Online (Sandbox Code Playgroud)

然后映射例如这些(应该是递归的,而不是 nnoremap):
<C-R>并且<CR>应该按字面输入。
\v在模式中意味着“非常神奇”,@!消极的前瞻。\2使用第二个括号中的内容。

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

然后执行,,任意次数,在您的示例中为 2 次。一为所有bs,一为所有cs。


编辑:映射的解释。我将使用问题中的示例,就好像它已经使用此映射运行过一次一样。
运行一圈后:

1. a
2. b
3. a
4. b
5. a
6. b
7. c
8. c
9. c
Run Code Online (Sandbox Code Playgroud)

然后光标位于最后a(第 5 行),当输入 时,,,它首先返回到第一行,然后运行映射 for ,.,该映射正在执行以下操作:

"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.
Run Code Online (Sandbox Code Playgroud)