Ric*_*sin 2 regex vim substitution
一个多行文档有一个标题/标题部分,然后每个下面有大约10个列表.我需要将标题/标题信息放入每个列表中,以便它们可以正确上传到网站(使用逗号和管道分隔符).它看起来像这样:
SectionName1 and TitleName1
1111 - The SubSectionName A
222 - The SubSectionName B
3333 - The SubSectionName C
SectionName2 and TitleName2
444 - The SubSectionName D
55555 - The SubSectionName E
66 - The SubSectionName F
Run Code Online (Sandbox Code Playgroud)
重复几百次.我需要的是产生类似的东西:
SectionName1,TitleName1,1111,SubSectionNameA
SectionName1,TitleName1,222,SubSectionNameB
SectionName1,TitleName1,3333,SubSectionNameC
SectionName2,TitleName2,444,SubSectionNameD
SectionName2,TitleName2,55555,SubSectionNameE
SectionName2,TitleName2,66,SubSectionNameF
Run Code Online (Sandbox Code Playgroud)
我意识到这个解决方案有多种方法,但是我很难在任何一种方法上触发触发器.我理解子匹配,连接和getline但我不擅长在这种情况下实际使用它们.
任何让我精神上开始的帮助将不胜感激.
让我提出以下非常一般的Ex命令来解决这个问题.1
:g/^\s*\h/d|let@"=substitute(@"[:-2],'\s\+and\s\+',',','')|ki|/\n\s*\h\|\%$/kj|
\ 'i,'js/^\s*\(\d\+\)\s\+-\s\+The/\=@".','.submatch(1).','/|'i,'js/\s\+//g
Run Code Online (Sandbox Code Playgroud)
在顶层,这是一个:global
命令,它枚举以零个或多个空格字符开头的行,后跟拉丁字母或下划线(请参阅参考资料:help /\h
).匹配此模式的行应该是包含节名和标题名称的标题行.在描述标题行的模式之后,命令的其余部分是要为每个行执行的指令.
要对标题执行的操作可以分为三个步骤.
删除当前标题行,同时从中提取节标题和标题名称.
:d|let@"=substitute(@"[:-2],'\s\+and\s\+',',','')
Run Code Online (Sandbox Code Playgroud)
首先,使用该:delete
命令删除当前行,将其保存到未命名的寄存器中.然后,将该寄存器的内容(称为@"
;参见:help @r
和:help ""
)更新为替换的结果,and
将由空白字符包围的单词改为单个逗号.实际更换由substitute()
功能执行.
但是,输入不是包含整个标题行的确切字符串,而是它的前缀省略了最后一个字符,即换行符号.该[:-2]
表示法是短形式
[0:-2]
标表达式,其指定从第一字节的子字符串以从端部(见第二个计数:help
expr-[:]
).这样,未命名的寄存器保存以逗号分隔的部分和标题名称.
确定从属分段线的范围.
:ki|/\n\s*\h\|\%$/kj
Run Code Online (Sandbox Code Playgroud)
在第一步之后,属于刚刚解析的标题行的子部分记录位于从当前行(标题之后的那一行)开始直到下一个标题行,或者如果下面没有这样的行,则是缓冲区的结尾.这些线的编号存储在标记i
和j
分别.(有关:helpg ^A mark
is
商标的说明,请参阅.)
:k
默认情况下,使用在给定范围的最后一行(即当前行)设置指定标记的命令放置标记.因此,与所考虑的块的第一行不同,最后一行需要特定的行范围来指出其位置.在这种情况下,使用特定形式的范围,表示给定模式匹配的下一行(请参阅参考资料:help :range
).定义要找到的行的位置的模式以这样的方式组成:它匹配紧接在标题之前的行(以可能的空格开头,后跟字母字符开头的行)或最后一行.(有关:help pattern
Vim正则表达式语法的详细信息,请参阅.)
根据所需的格式转换描绘的子部分行,在相应的标题行中找到前面的部分和标题名称.
:'i,'js/^\s*\(\d\+\)\s\+-\s\+The/\=@".','.submatch(1).','/|'i,'js/\s\+//g
Run Code Online (Sandbox Code Playgroud)
此步骤包含两个:substitute
命令,这两个命令在由标记i
和j
(参见:help [range]
)标记的位置分隔的行范围上运行.
第一个替换命令匹配子部分行的开头 - 后跟连字符的标识符和单词The
,全部浮动在空白中 - 并用未命名的寄存器的内容替换它,保持部分和标题名称用逗号连接,匹配的标识符和另一个逗号.第二个替换通过挤压线上的所有空白字符来完成转换,以将子部分名称和后面的字母拼接在一起.
要在第一个:substitute
命令中构造替换字符串,请使用substitute-with-an-expression功能(请参阅参考资料:help
sub-replace-\=
).命令的替换部分应该从\=
Vim 开始,不是以常规方式解释剩余的文本,而是作为表达式(参见参考资料:help expression
).该表达式的评估结果成为替换字符串.请注意submatch()
,在替换表达式中使用该函数可以按其编号检索子匹配的文本.
1 命令被包装以获得更好的可读性,下面列出了它的单行版本,以便于复制粘贴到Vim命令行.请注意,wrapped命令可以在Vim脚本中使用而不做任何更改.
:g/^\s*\h/d|let@"=substitute(@"[:-2],'\s\+and\s\+',',','')|ki|/\n\s*\h\|\%$/kj|'i,'js/^\s*\(\d\+\)\s\+-\s\+The/\=@".','.submatch(1).','/|'i,'js/\s\+//g
Run Code Online (Sandbox Code Playgroud)