我继承了一组带有缩进目录列表的文件,如下所示:

DirA /
DirA1 /
DirA2 /
DirA2.1 /
DirA3 /
DirB /
目录/
目录C1 /
DirC1.1 /
目录C1.1.1 /
DirC1.2 /

为了移植到新代码和新结构,我需要将其更改为每一行的完整路径。

DirA /
DirA / DirA1 /
DirA / DirA2 /
DirA / DirA2 / DirA2.1 /
DirA / DirA3 /
DirB /
目录/
DirC / DirC1 /
DirC / DirC1 / DirC1.1 /
DirC / DirC1 / DirC1.1 / DirC1.1.1 /
DirC / DirC1 / DirC1.2 /

我宁愿为此使用vim(如果只是为了增加我的vim功能),但我还没有找到如何做到这一点(使用正则表达式,寄存器和/或宏?)。有人可以给我一些指示吗?我会很感激的。

最佳答案

假设缩进宽度为2个空格:

:%s#^\s\+#\=join(split(getline(line('.')-1),'/')[:strlen(submatch(0))/2-1],'/').'/'

总览

这个想法是获取上一行(getline(line('.')-1))并将该行拆分为目录。然后在前导空格处进行替换,并根据缩进级别strlen(submatch(0))/2-1用上一行的目录列表的子列表替换。

细节荣耀
  • %s#^\s\+#{replacement}-对以空格开头的行进行替换
  • \={expr}将产生{expr}的结果作为空格的替换-这称为子替换表达式
  • getline(line('.')-1)-获取上一行
  • split(getline(line('.')-1), '/')-将前几行分成目录段
  • lst[{start}:{end}]-从列表lst创建一个子列表,从{start}开始到索引{end}结束。
  • lst[:{end}]-假定列表的开始。例如[0,1,2][:1]产生[0,1]
  • submatch(0)-在子替换表达式submatch({n}内将获取捕获组编号{n}
  • submatch(0)将产生替换的整个匹配模式。正常替换
  • 中的aka \0&
  • strlen(submatch(0))/2将获得当前行的缩进级别
  • strlen(submatch(0))/2-1将减少1个缩进级别。又名当前行和上面的行在
  • 中具有的目录结构部分
  • join({lst}, {glue})-将列表作为字符串连接在一起,并以{glue}作为列表项之间的分隔符
  • /取出的末尾添加一个split()
  • 重要的是要知道Vim从顶部开始逐行进行替换(如@Lieven Keersmaekers所指出)。这意味着我们可以使用上一行来获取共同祖先

  • 有关更多帮助,请参见:
    :h :s
    :h sub-replace-expression
    :h getline()
    :h line()
    :h join()
    :h sublist
    :h strlen()
    :h split()
    

    10-02 02:31