2013-02-10 84 views
6

我想隔行扫描三组文本行。例如从隔行行vim

a 
a 
a 
b 
b 
b 
c 
c 
c 

去要

a 
b 
c 
a 
b 
c 
a 
b 
c 

是否有这样做的有效途径?

+0

这是真实世界的情况还是减少的测试用例? – romainl 2013-02-10 07:23:27

+0

减少测试用例。有三组需要隔行扫描,但每个组合需要更长的时间。我可以对一个宏,但我认为可能有一个更好的方法:g和移动 – jpiasetz 2013-02-10 07:29:48

+0

嗯,如果所有'a's是相同的和'b's是相同的和'c's是相同的我' d只需手动命令第一个'abc'(':/ b/m。',':/ c/m.')并将结果块复制3次(这很快),但是您的真实世界需求可能更复杂。 – romainl 2013-02-10 07:43:44

回答

0

这里是一个“oneliner”(差不多),但你必须要重做它为每一个独特的路线减1,在你的榜样2倍。也许没用,但我认为这是一个很好的练习,可以更多地了解VIM中的模式。只要整条线是唯一的(例如mnomnp是两条独特的线),它就可以处理所有种类的线。

首先确保这(做已经/映射到任何东西,或其他任何在该行):

: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。


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

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将只是正常交错。有2个参数,它将会指定多少个组合在一起。例如​​将从顶部取2行,然后从底部取1行进行交织。

我们解决您的问题

:1,/c/-1Interleave 
:Interleave 2 1 
  • 1,/c/-1范围内开始的第一行和结束1行匹配信c第一线之上。
  • :1,/c/-1Interleave基本上交织的a组的和b
  • ​​范围此时整个文件。
  • ​​将ab的混合组与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 
+0

有趣的[交叉](http://vi.stackexchange.com/a/4576/2978)? ;) – 2016-02-24 09:02:18

1

我刚刚在今晚独自遇到了这个问题。我的问题不像一些答案那样优雅,但是我认为它更容易理解。它使许多假设,所以这是一个黑客攻击的一位:

  • A)它假定有一些独特的字符(或任意字符 字符串)不存在任何线路的 - 我想下面@
  • B)它 假定您不希望在任何 a,b或c节中的前导或尾随空白。
  • C)它假定可以很容易地识别 最大行长度,然后垫所有线是长度(例如 可能使用%!成AWK或等等,用printf)

    1. 垫所有具有相同最大长度的空格的行。
    2. Visual仅选择a和b部分,然后%s/$/@
    3. 将块复制并越过b部分以在c部分之前。
    4. 将块复制并粘贴到bc部分的前面。
    5. %s/@/\r
    6. %s/^ *//g
    7. %s/ *$//g
    8. 删除线左其中a和b切片。
0

如果你有xclip你可以剪切线和使用paste交织他们:

  1. 视觉选择一组线
  2. 类型"+d将它们剪切到剪贴板
  3. 目视选择另一组线
  4. 类型!paste -d '\n' /dev/stdin <(xclip -o -selection clipboard)