如何使用正则表达式将换行符转换为缩进



我有一个看起来像这样的列表:

Item 1

Subitem 1
Item 2
Item 3

Subitem 1

Subitem 2

Subsubitem 1
Item 4

基本上,每个顶级项前面都有一个换行符,每个子项有两个换行符,子子项有三个换行符,以此类推。我希望它的格式类似于:

Item 1
    Subitem 1
Item 2
Item 3
    Subitem 1
    Subitem 2
        Subsubitem 1
Item 4

我在vim中使用的正则表达式是:

第一级:

%s/^$n(tw)/t1/g

第二层:

%s/^$n(ttw)/t1/g

等等。

有什么更好的方法可以做到这一点,而不必为列表的每个级别运行不同的正则表达式?我试图使用vim来做到这一点,但任何*nix解决方案对我来说都很好。

这取决于是什么在执行正则表达式。例:Sed在解析行时不能达到这个目的。如果您正在使用sed,请尝试将其替换为tr:

tr 'n' 't'

Perl方式:

perl -0777pe 's/nKn+/"t"x(-1+length $&)/gse'

使用tr和GNU sed:

tr 'n' 't' | sed -E 's/([^t])tt/1n/g'
输出:

Item 1
        Subitem 1
Item 2
Item 3
        Subitem 1
        Subitem 2
                Subsubitem 1
Item 4

这可以通过:s和子替换表达式(=)来完成。

:%s/^n+/=repeat("t",len(submatch(0))-1)/

基本上我们计算n '的数量,并用相同数量的t '替换它们。

  • :%s/^n+/.../g查找n的序列
  • %s/.../={expr}/g用表达式{expr}的求值代替匹配。
  • submatch(0)得到第n个子匹配。与&相同。
  • repeat({str}, {num})返回字符串,{str}重复{num}次。
  • {str} . len({str}) . get length of string .
  • len(submatch(0))-1递减长度,因为我们希望保持"好行"在单独的行上。

更多帮助参见:

:h :s
:h sub-replace-expression
:h :repeat()
:h :len()
:h submatch()

您可以做的一件事是递归地使用以下正则表达式:

(?<!n)nt*n

递归地查找并替换此正则表达式

的所有出现
  • 第一次传递替换为:n
  • 第二遍替换为:nt
  • 第三遍替换为:ntt
  • 第四遍替换为:nttt

…以此类推,直到在任何地方都找不到匹配的正则表达式。

所以你不必每次都运行一个不同的正则表达式,但是你仍然需要改变replace with part。您可以编写一个小程序来递归地执行此操作。

最新更新