Regex 使用vim将缩进目录列表转换为完整路径
我继承了一组带有缩进目录列表的文件,如下所示: DirA/ DirA1/ DirA2/ DirA2.1/ DirA3/ DirB/ DirC/ DirC1/ DirC1.1/ DirC1.1.1/ DirC1.2/ 迪拉/ 迪拉1/ 迪拉2/ DirA2.1/ 迪拉3/ 肮脏的/ 迪尔克/ DirC1/ 目录1.1/ 第1.1.1条/ 第1.2节/ 为了迁移到新代码和新结构,我需要在每一行上将其更改为完整路径 DirA/ DirA/DirA1/ DirA/DirA2/ DirA/DirA2/DirA2.1/ DirA/DirA3/ DirB/ DirC/ DirC/DirC1/ DirC/DirC1/DirC1.1/ DirC/DirC1/DirC1.1/DirC1.1.1/ DirC/DirC1/DirC1.2/ 迪拉/ DirA/DirA1/ DirA/DirA2/ DirA/DirA2/DirA2.1/ DirA/DirA3/ 肮脏的/ 迪尔克/ DirC/DirC1/ DirC/DirC1/DirC1.1/ DirC/DirC1/DirC1.1/DirC1.1.1/ DirC/DirC1/DirC1.2/Regex 使用vim将缩进目录列表转换为完整路径,regex,vim,Regex,Vim,我继承了一组带有缩进目录列表的文件,如下所示: DirA/ DirA1/ DirA2/ DirA2.1/ DirA3/ DirB/ DirC/ DirC1/ DirC1.1/ DirC1.1.1/ DirC1.2/ 迪拉/ 迪拉1/ 迪拉2/ DirA2.1/ 迪拉3/ 肮脏的/ 迪尔克/ DirC1/ 目录1.1/ 第1.1.1条/ 第1.2节/ 为了迁移到新代码和新结构,我需要在每一行上将其更改为完整路径 DirA/ DirA/DirA1/
我更愿意为此使用
vim
(如果只是为了增加我的vim fuu),但我还没有找到如何做到这一点(使用正则表达式、寄存器和/或宏?)。谁能给我一些指点吗?非常感谢。你能试试这个正则表达式吗:
/^(.+\/)((\r?\n(\s\s){1,}\S+){0,})\r?\n\s\s(\S+)/gm
并替换为以下内容之一:
$1$2\n$1$5
$1$2\r\n$1$5
(如果需要\n
换行符或\r\n
)
演示:
工作原理:
- 捕获第一个目录(之前没有
)\s
- 捕获所有行,直到行有
,而下一行开头没有\s\s
。它是最后一个子目录\s
- 将父目录添加到最后一个子目录并删除
\s\s
- 继续这个循环李>
- 对于接下来的步骤,将最后一个
更改为\s\s
和下一个\s{4}
,然后\s{6}
我不知道
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}
-假设列表开始。e、 glst[:{end}]
产生[0,1,2][:1]
[0,1]
-在子替换表达式中submatch(0)
将获取捕获组编号,submatch({n}
{n}
将生成替换的整个匹配模式。在正常替换中,也称为子匹配(0)
或\0
&
将获取当前行的缩进级别strlen(子匹配(0))/2
将减少1个缩进级别。aka。当前行和上面的行共同拥有的目录结构部分strlen(submatch(0))/2-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()
我只是用在线工具测试我的答案,它是有效的。如果你有任何问题,让我们知道!OP正试图通过将父目录包含到每个子目录来将文本从文件1更改为文件2。我认为此文本是输入,需要更改为新文本@Meninx-メネンックス因此,您知道您的解决方案并没有回答OP的问题!感谢您的建议。我使用了Peter的oneliner,因为学习它更有趣,而且它是解决我所面临问题的一步解决方案。但是就像在perl中一样,vim有不止一种方法来做事情。哦,天哪。我们真的需要类似excel的功能来评估一步一步地评估一个公式。我可以算出其中的大部分,但试图将它应用到一行上,这让我很头疼。你可能想补充一点,这是有效的,因为vim一行一行地替换了一行,所以你有(并且需要)替换掉当前行的行-1(我希望我能说清楚)。下面的
[:]
返回列表子集的符号可能也值得一提。我从您的oneliner(再次)中学到了很多,tx.@LievenKeersmaekers我已经将其转换为一个替换并添加了一个descriptionI我实际上喜欢全局命令,因为它教会了我额外的东西,但是vimwise,更短更好。这一个在我的vimtips中!@Theoturi,getline(line('.)-1)
将产生一个空字符串。你可以通过:echo getline(0)来测试它
。我通过对模式使用^\s\+
而不是^\s*
来避免此问题。这确保了始终存在父目录。