我继承了一组带有缩进目录列表的文件,如下所示:
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)
将产生替换的整个匹配模式。正常替换\0
或&
strlen(submatch(0))/2
将获得当前行的缩进级别strlen(submatch(0))/2-1
将减少1个缩进级别。又名当前行和上面的行在join({lst}, {glue})
-将列表作为字符串连接在一起,并以{glue}
作为列表项之间的分隔符/
取出的末尾添加一个split()
有关更多帮助,请参见:
:h :s
:h sub-replace-expression
:h getline()
:h line()
:h join()
:h sublist
:h strlen()
:h split()