VIM宏:特殊排序:howto?

时间:2012-01-30 16:20:24

标签: vim macros

这是我的清单:

Word1
Word2
...
Word4 / Word5 Word6
Word7
Word8 Word9 Word10 / Word11 Word12 Word13 Word14
Word15
Word16
...

这就是我想要的:

Word1
Word2
...
Word4 Word6
Word5 Word6
Word7
Word8 Word9 Word10 Word14
Word11 Word12 Word13 Word14
Word15
Word16
...

即。有时在一组1,2或3个单词之间有一个斜杠/(让我们称之为g1g2),在这些“组”之后,还有更多单词(让我们叫他们g3)。我想在这两行中分解这一行:第1行= g1 g3,第2行= g2 g3

您可以在一个宏中执行此操作还是解释如何执行此操作?

3 个答案:

答案 0 :(得分:2)

您可以将function写入expand slash

fun! ExpandSlash() range
    for i in range(a:firstline, a:lastline)
        let ws = split(getline(i))
        let idx = index(ws, '/')
        if idx==-1
            continue
        endif
        let h= join(ws[ : idx-1])
        let m= join(ws[idx+1 : 2*idx])
        let t= join(ws[2*idx+1 : ])
        call setline(i, h.' '.t.'/'.m.' '.t)
    endfor
endfun

:%call ExpandSlash()
:%s@/@\r@

1 2 3 / 4 5 6 7 8

1 2 3 7 8
4 5 6 7 8

答案 1 :(得分:2)

可以使用以下单个命令执行整个操作。

:g~/~s~\s*/\s*~\r~|-|exe's/\ze\n\%(\s*\w\+\)\{'.len(split(getline('.'))).'}\(.*\)$/\1'

:global命令选择与模式/匹配的行(此处为 由~字符包围),并执行后面的命令 每一行。让我们逐一考虑它们。

  1. 具有可选周围空格的斜杠字符,即 分隔当前行上的第一组和第二组单词 (就问题的陈述而言),被换行符取代 字符,

    :s~\s*/\s*~\r~
    

    此处,波形符再次用于分隔图案和 替换字符串,这样就不需要转义斜杠了。

  2. 替换后,光标位于旁边的行上 /所在的地方。为了方便下一个命令的措辞, 光标向上移动一行,

    :-
    

    -是表示该行的.-1范围的缩写 在当前的一个之前(见:help :range)。

  3. 第三组单词,现在位于下一行的末尾,是 被附加到当前的。为了做到这一点,数量 确定第一组中的单词。自当前行 仅包含第一个组,该数字由计算得出 将行的内容分隔为以空格分隔的组 使用split()函数

    len(split(getline('.')))
    

    getline('.')将当前行作为字符串split()返回 将该字符串转换为单词列表,len()计算该数字 列表中的项目。)

    使用该数量的单词,生成替换命令 使用:execute命令运行

    :exe's/\ze\n\%(\s*\w\+\)\{'.len(split(getline('.'))).'}\(.*\)$/\1'
    

    替换具有以下结构,

      

    :s/\ze\n\%(\s*\w\+\)\{ N }\(.*\)$/\1

    其中 N 是放在之前的字数 斜线。

    模式匹配当前行的换行符 通过第二行上的 N 字词。一个单词匹配为 一系列一个或多个单词之前的空格序列 字符(请参阅:help /\s:help /\w)。单词模式是 括在\%(\)转义括号(请参阅:help /\%()之间,将其视为\{N}说明符的单个原子(请参阅 :help /\{)完全匹配 N 次出现。该 剩下的文本到下一行的末尾被匹配为一个子组 在替换字符串中引用。

    由于模式最开始的\ze原子,因此 match的宽度为零(参见:help /\ze)。所以,替代 用带有文本的换行符替换该空字符串 由子组匹配,从而插入第三组单词 第一个。

答案 2 :(得分:0)

对于给定的示例,结果相当于将每个/替换为行上的最后一个单词和换行符\r。这是一个全局替代命令:

:%s#/ \ze.*\(\<\w\+$\)#\1\r#

说明:

  • / \ze匹配/结束匹配(\ze将被替换后没有任何内容)
  • .*匹配任何中间字符
  • \(启动另一个匹配组
  • \<\w\+$匹配行尾之前的最后一个字
  • \)停止匹配组

但是,然后您说尾随组g3可能包含多个单词,这意味着替换操作需要能够计算/之前和之后的单词数。我担心我不知道该怎么做,但我相信不久有人会跳过你的救援!